CM3D2 Converter.model_import
1import os 2import math 3import struct 4import time 5import traceback 6import bpy 7import bpy_extras 8import bmesh 9import mathutils 10from collections import Counter 11from . import common 12from . import compat 13from . import cm3d2_data 14from .translations.pgettext_functions import * 15from .misc_OBJECT_PT_transform import CNV_OT_align_to_cm3d2_base_bone 16 17 18# メインオペレーター 19@compat.BlRegister() 20#@bpy_extras.io_utils.orientation_helper(axis_forward='-Z', axis_up='Y') 21class CNV_OT_import_cm3d2_model(bpy.types.Operator, bpy_extras.io_utils.ImportHelper): 22 bl_idname = 'import_mesh.import_cm3d2_model' 23 bl_label = "CM3D2モデル (.model)" 24 bl_description = "カスタムメイド3D2のmodelファイルを読み込みます" 25 bl_options = {'REGISTER'} 26 27 filepath = bpy.props.StringProperty(subtype='FILE_PATH') 28 filename_ext = ".model" 29 filter_glob = bpy.props.StringProperty(default="*.model", options={'HIDDEN'}) 30 31 scale = bpy.props.FloatProperty(name="倍率", default=5, min=0.1, max=100, soft_min=0.1, soft_max=100, step=100, precision=1, description="インポート時のメッシュ等の拡大率です") 32 33 is_mesh = bpy.props.BoolProperty(name="メッシュ生成", default=True, description="ポリゴンを読み込みます、大抵の場合オンでOKです") 34 is_remove_doubles = bpy.props.BoolProperty(name="重複頂点を結合", default=True, description="UVの切れ目でポリゴンが分かれている仕様なので、インポート時にくっつけます") 35 is_seam = bpy.props.BoolProperty(name="シームをつける", default=True, description="UVの切れ目にシームをつけます") 36 is_sharp = bpy.props.BoolProperty(name="Mark Sharp", default=True, description="This will mark removed doubles on your mesh as sharp (or all free edges if not removing doubles).") 37 38 is_convert_bone_weight_names = bpy.props.BoolProperty(name="頂点グループ名をBlender用に変換", default=False, description="全ての頂点グループ名をBlenderの左右対称編集で使えるように変換してから読み込みます") 39 is_vertex_group_sort = bpy.props.BoolProperty(name="頂点グループを名前順ソート", default=True, description="頂点グループを名前順でソートします") 40 is_remove_empty_vertex_group = bpy.props.BoolProperty(name="割り当てのない頂点グループを削除", default=True, description="全ての頂点に割り当てのない頂点グループを削除します") 41 42 reload_tex_cache = bpy.props.BoolProperty(name="テクスチャキャッシュを再構成", default=False, description="texファイルを探す際、キャッシュを再構成します") 43 is_decorate = bpy.props.BoolProperty(name="種類に合わせてマテリアルを装飾", default=True) 44 is_mate_data_text = bpy.props.BoolProperty(name="テキストにマテリアル情報埋め込み", default=True, description="シェーダー情報をテキストに埋め込みます") 45 46 is_armature = bpy.props.BoolProperty(name="アーマチュア生成", default=True, description="ウェイトを編集する時に役立つアーマチュアを読み込みます") 47 is_armature_clean = bpy.props.BoolProperty(name="不要なボーンを削除", default=False, description="ウェイトが無いボーンを削除します") 48 is_custom_bones = bpy.props.BoolProperty(name="Use Custom Bones", default=False, description="Use the currently selected object for custom bone shapes.") 49 is_use_local_bones = bpy.props.BoolProperty(name="Use Local Bones", default=True, description="Use the Local Bone Data for orientation (more accurate)") 50 51 is_bone_data_text = bpy.props.BoolProperty(name="テキスト", default=True, description="ボーン情報をテキストとして読み込みます") 52 is_bone_data_obj_property = bpy.props.BoolProperty(name="オブジェクトのカスタムプロパティ", default=True, description="メッシュオブジェクトのカスタムプロパティにボーン情報を埋め込みます") 53 is_bone_data_arm_property = bpy.props.BoolProperty(name="アーマチュアのカスタムプロパティ", default=True, description="アーマチュアデータのカスタムプロパティにボーン情報を埋め込みます") 54 texpath_dict = None 55 56 @classmethod 57 def poll(cls, context): 58 return True 59 60 def invoke(self, context, event): 61 prefs = common.preferences() 62 if prefs.model_default_path: 63 self.filepath = common.default_cm3d2_dir(prefs.model_default_path, None, "model") 64 else: 65 self.filepath = common.default_cm3d2_dir(prefs.model_import_path, None, "model") 66 self.scale = prefs.scale 67 self.is_convert_bone_weight_names = prefs.is_convert_bone_weight_names 68 if compat.IS_LEGACY or bpy.app.version < (2, 91): 69 self.is_sharp = False 70 context.window_manager.fileselect_add(self) 71 return {'RUNNING_MODAL'} 72 73 def draw(self, context): 74 prefs = common.preferences() 75 self.layout.prop(self, 'scale') 76 77 box = self.layout.box() 78 box.prop(self, 'is_mesh', icon='MESH_DATA') 79 80 sub_box = box.box() 81 sub_box.enabled = self.is_mesh 82 sub_box.label(text="メッシュ") 83 sub_box.prop(self, 'is_remove_doubles', icon='STICKY_UVS_VERT') 84 sub_box.prop(self, 'is_seam' , icon=compat.icon('UV_EDGESEL')) 85 if not compat.IS_LEGACY and bpy.app.version >= (2, 91): 86 sub_box.prop(self, 'is_sharp', icon=compat.icon('EDGESEL')) 87 88 sub_box = box.box() 89 sub_box.enabled = self.is_mesh 90 sub_box.label(text="頂点グループ") 91 sub_box.prop(self, 'is_vertex_group_sort', icon='SORTALPHA') 92 sub_box.prop(self, 'is_remove_empty_vertex_group', icon='DISCLOSURE_TRI_DOWN') 93 sub_box.prop(self, 'is_convert_bone_weight_names', icon='BLENDER') 94 95 sub_box = box.box() 96 sub_box.enabled = self.is_mesh 97 sub_box.label(text="マテリアル") 98 sub_box.prop(prefs, 'is_replace_cm3d2_tex', icon='BORDERMOVE') 99 sub_box.prop(self, 'reload_tex_cache', icon='FILE_REFRESH') 100 if compat.IS_LEGACY: 101 sub_box.prop(self, 'is_decorate', icon=compat.icon('SHADING_TEXTURE')) 102 sub_box.prop(self, 'is_mate_data_text', icon='TEXT') 103 104 box = self.layout.box() 105 box.prop(self, 'is_armature', icon='ARMATURE_DATA') 106 107 sub_box = box.box() 108 sub_box.label(text="アーマチュア") 109 sub_box.prop(self , 'is_use_local_bones' , icon=compat.icon('GROUP_BONE'), text="Use Local Bone Data") 110 sub_box.prop(self , 'is_armature_clean' , icon=compat.icon('X' )) 111 sub_box.prop(self , 'is_convert_bone_weight_names', icon=compat.icon('BLENDER' ), text="ボーン名をBlender用に変換") 112 sub_box.prop(prefs, 'show_bone_in_front' , icon=compat.icon('HIDE_OFF' ), text="Show Bones in Front") 113 row = sub_box.row() 114 row.prop (self , 'is_custom_bones' , icon=compat.icon('BONE_DATA' ), text="Use Selected as Bone Shape" ) 115 row.enabled = bool(context.object) 116 117 box = self.layout.box() 118 box.label(text="ボーン情報埋め込み場所") 119 box.prop(self, 'is_bone_data_text', icon='TEXT') 120 box.prop(self, 'is_bone_data_obj_property', icon='OBJECT_DATA') 121 box.prop(self, 'is_bone_data_arm_property', icon='ARMATURE_DATA') 122 123 def execute(self, context): 124 start_time = time.time() 125 126 prefs = common.preferences() 127 prefs.model_import_path = self.filepath 128 prefs.scale = self.scale 129 context.window_manager.progress_begin(0, 10) 130 context.window_manager.progress_update(0) 131 132 custom_bone_ob = context.active_object 133 if not custom_bone_ob: 134 self.is_custom_bones = False 135 136 #global_matrix = bpy_extras.io_utils.axis_conversion(from_forward=self.axis_forward, from_up=self.axis_up).to_4x4() 137 138 try: 139 reader = open(self.filepath, 'rb') 140 except: 141 self.report(type={'ERROR'}, message=f_tip_("ファイルを開くのに失敗しました、アクセス不可かファイルが存在しません。file={}", self.filepath)) 142 return {'CANCELLED'} 143 144 self.texpath_dict = common.get_texpath_dict(reload=self.reload_tex_cache) 145 146 with reader: 147 # ヘッダー 148 ext = None 149 try: # luvoid : utf-8 decoding could possibly throw an error here 150 ext = common.read_str(reader) 151 except: 152 ext = False 153 if ext != 'CM3D2_MESH': 154 self.report(type={'ERROR'}, message="これはカスタムメイド3D2のモデルファイルではありません") 155 return {'CANCELLED'} 156 model_ver = struct.unpack('<i', reader.read(4))[0] 157 self.report(type={'INFO'}, message=f_tip_("Model Version = {version}", version=model_ver)) 158 context.window_manager.progress_update(0.1) 159 160 try: 161 # 名前群を取得 162 model_name1 = common.read_str(reader) 163 model_name2 = common.read_str(reader) 164 context.window_manager.progress_update(0.2) 165 166 # ボーン情報読み込み 167 bone_data = [] 168 bone_count = struct.unpack('<i', reader.read(4))[0] 169 for i in range(bone_count): 170 name = common.read_str(reader) 171 scl = struct.unpack('<B', reader.read(1))[0] 172 bone_data.append({'name': name, 'scl': scl}) 173 174 for i in range(bone_count): 175 parent_index = struct.unpack('<i', reader.read(4))[0] 176 parent_name = None 177 if parent_index != -1: 178 parent_name = bone_data[parent_index]['name'] 179 bone_data[i]['parent_index'] = parent_index 180 bone_data[i]['parent_name'] = parent_name 181 182 for i in range(bone_count): 183 x, y, z = struct.unpack('<3f', reader.read(3*4)) 184 bone_data[i]['co'] = mathutils.Vector((x, y, z)) 185 186 x, y, z = struct.unpack('<3f', reader.read(3*4)) 187 w = struct.unpack('<f', reader.read(4))[0] 188 bone_data[i]['rot'] = mathutils.Quaternion((w, x, y, z)) 189 if model_ver >= 2001: 190 use_scale = struct.unpack('<B', reader.read(1))[0] 191 if use_scale: 192 print(bone_data[i]['name'],"has scale data!") 193 scale_x, scale_y, scale_z = struct.unpack('<3f', reader.read(3*4)) 194 bone_data[i]['scale'] = [scale_x, scale_y, scale_z] 195 196 context.window_manager.progress_update(0.3) 197 198 print(f_("Reading vertex, mesh, and local bone count at 0x{num:02X}", num=reader.tell())) 199 vertex_count, mesh_count, local_bone_count = struct.unpack('<3i', reader.read(3*4)) 200 201 # ローカルボーン情報読み込み 202 local_bone_data = [] 203 for i in range(local_bone_count): 204 local_bone_data.append({'name': common.read_str(reader)}) 205 206 for i in range(local_bone_count): 207 row0 = struct.unpack('<4f', reader.read(4 * 4)) 208 row1 = struct.unpack('<4f', reader.read(4 * 4)) 209 row2 = struct.unpack('<4f', reader.read(4 * 4)) 210 row3 = struct.unpack('<4f', reader.read(4 * 4)) 211 local_bone_data[i]['matrix'] = mathutils.Matrix([row0, row1, row2, row3]) 212 context.window_manager.progress_update(0.4) 213 214 # 頂点情報読み込み 215 vertex_data = [] 216 print(f_("Reading vertex data at 0x{num:02X}", num=reader.tell())) 217 extra_uv_uses = [False] * 7 218 if model_ver >= 2102: # CR Edit Mode 219 extra_uv_uses = struct.unpack('<7?', reader.read(7)) 220 print(f_("extra_uv_uses = {boollist}", boollist=extra_uv_uses)) 221 for i in range(vertex_count): 222 co = struct.unpack('<3f', reader.read(3 * 4)) 223 no = struct.unpack('<3f', reader.read(3 * 4)) 224 uv = struct.unpack('<2f', reader.read(2 * 4)) 225 extra_uvs = [] # CR Edit 226 for i, used in enumerate(extra_uv_uses): 227 if used: 228 extra_uvs.append(struct.unpack('<2f', reader.read(2 * 4))) 229 vertex_data.append({'co': co, 'normal': no, 'uv': uv, 'extra_uvs': extra_uvs}) 230 if self.is_remove_doubles: 231 comparison_data = list(hash(repr(v['co']) + " " + repr(v['normal'])) for v in vertex_data) 232 comparison_counter = Counter(comparison_data) 233 comparison_data = list((comparison_counter[h] > 1) for h in comparison_data) 234 del comparison_counter 235 print(f_("Reading unknown count at 0x{num:02X}", num=reader.tell())) 236 unknown_count = struct.unpack('<i', reader.read(4))[0] 237 for i in range(unknown_count): 238 struct.unpack('<4f', reader.read(4 * 4)) 239 for i in range(vertex_count): 240 indexes = struct.unpack('<4H', reader.read(4 * 2)) 241 values = struct.unpack('<4f', reader.read(4 * 4)) 242 vertex_data[i]['weights'] = list({ 243 'index': index, 244 'value': value, 245 'name': local_bone_data[index]['name'], 246 } for index, value in zip(indexes, values)) 247 context.window_manager.progress_update(0.5) 248 # 面情報読み込み 249 face_data = [] 250 for i in range(mesh_count): 251 face_count = int(struct.unpack('<i', reader.read(4))[0] / 3) 252 datum = [tuple(reversed(struct.unpack('<3H', reader.read(3 * 2)))) for j in range(face_count)] 253 face_data.append(datum) 254 context.window_manager.progress_update(0.6) 255 256 # マテリアル情報読み込み 257 # TODO MaterialHandlerに変更 258 material_data = [] 259 material_count = struct.unpack('<i', reader.read(4))[0] 260 for i in range(material_count): 261 print(f_("mate count: {num} of {count} @ 0x{pos:02X}", num=i, count=material_count, pos=reader.tell())) 262 data = cm3d2_data.MaterialHandler.read(reader, read_header=False, version=model_ver) 263 data.name1 = data.name.lower() 264 material_data.append(data) 265 266 # name1 = common.read_str(reader) 267 # name2 = common.read_str(reader) 268 # name3 = common.read_str(reader) 269 # data_list = [] 270 # material_data.append({'name1': name1, 'name2': name2, 'name3': name3, 'data': data_list}) 271 # while True: 272 # data_type = common.read_str(reader) 273 # if data_type == 'tex': 274 # data_item = {'type': data_type} 275 # data_list.append(data_item) 276 # data_item['name'] = common.read_str(reader) 277 # data_item['type2'] = common.read_str(reader) 278 # if data_item['type2'] == 'tex2d': 279 # data_item['name2'] = common.read_str(reader) 280 # data_item['path'] = common.read_str(reader) 281 # data_item['tex_map'] = struct.unpack('<4f', reader.read(4*4)) 282 # elif data_type == 'col': 283 # name = common.read_str(reader) 284 # col = struct.unpack('<4f', reader.read(4*4)) 285 # data_list.append({'type': data_type, 'name': name, 'color': col}) 286 # elif data_type == 'f': 287 # name = common.read_str(reader) 288 # fval = struct.unpack('<f', reader.read(4))[0] 289 # data_list.append({'type': data_type, 'name': name, 'float': fval}) 290 # else: 291 # break 292 293 context.window_manager.progress_update(0.8) 294 295 # その他情報読み込み 296 misc_data = [] 297 while True: 298 #print(f_("Reading data_type at 0x{num:02X}", num=reader.tell())) 299 data_type = common.read_str(reader) 300 if data_type == 'morph': 301 misc_item = {'type': data_type} 302 misc_data.append(misc_item) 303 misc_item['name'] = common.read_str(reader) 304 misc_item['data'] = data_list = [] 305 morph_vert_count = struct.unpack('<i', reader.read(4))[0] 306 morph_extra_uvs = False 307 if model_ver >= 2102: # CR Edit Mode 308 morph_extra_uvs = struct.unpack('<?', reader.read(1))[0] 309 misc_item['uvs'] = [] 310 print(f_("{morph}.morph_extra_uvs @ 0x{pos:02X} = {bool}", morph=misc_item['name'], bool=morph_extra_uvs, pos=reader.tell()-1)) 311 for i in range(morph_vert_count): 312 index = struct.unpack('<H', reader.read(2))[0] 313 co = mathutils.Vector(struct.unpack('<3f', reader.read(3 * 4))) 314 normal = struct.unpack('<3f', reader.read(3 * 4)) 315 extra_uvs = () # CR Edit 316 if morph_extra_uvs: 317 extra_uvs = struct.unpack('<4f', reader.read(4 * 4)) 318 data_list.append({'index': index, 'co': co, 'normal': normal, 'color': extra_uvs}) 319 else: 320 break 321 322 except UnicodeDecodeError as e: 323 msg = [ 324 f_tip_("Error reading file at byte 0x{num:02X}", num=reader.tell()-len(e.object)) + "\n", 325 str(e) + "\n", 326 *traceback.format_tb(e.__traceback__) 327 ] 328 self.report(type={'ERROR'}, message="".join(reversed(msg))[0:-1]) 329 print("".join(msg)) 330 return {'CANCELLED'} 331 332 except struct.error as e: 333 msg = [ 334 f_tip_("Error reading file at byte 0x{num:02X}", num=reader.tell()) + "\n", 335 str(e) + "\n", 336 *traceback.format_tb(e.__traceback__) 337 ] 338 self.report(type={'ERROR'}, message="".join(reversed(msg))[0:-1]) 339 print("".join(msg)) 340 return {'CANCELLED'} 341 342 except common.CM3D2ImportException as e: 343 msg = [ 344 f_tip_("Error reading file at byte 0x{num:02X}", num=reader.tell()) + "\n", 345 str(e) + "\n", 346 *traceback.format_tb(e.__traceback__) 347 ] 348 self.report(type={'ERROR'}, message="".join(reversed(msg))[0:-1]) 349 print("".join(msg)) 350 return {'CANCELLED'} 351 352 context.window_manager.progress_update(1) 353 354 try: 355 bpy.ops.object.mode_set(mode='OBJECT') 356 except RuntimeError: 357 pass 358 bpy.ops.object.select_all(action='DESELECT') 359 360 # アーマチュア作成 361 if self.is_armature: 362 arm = bpy.data.armatures.new(model_name1 + ".armature") 363 arm_ob = bpy.data.objects.new (model_name1 + ".armature", arm) 364 compat.link(bpy.context.scene, arm_ob) 365 compat.set_select(arm_ob, True) 366 compat.set_active(context, arm_ob) 367 368 arm.show_names = prefs.show_bone_names 369 arm.show_axes = prefs.show_bone_axes 370 arm.show_bone_custom_shapes = prefs.show_bone_custom_shapes 371 arm.show_group_colors = prefs.show_bone_group_colors 372 if compat.IS_LEGACY: 373 arm_ob.show_x_ray = prefs.show_bone_in_front 374 else: 375 arm_ob.show_in_front = prefs.show_bone_in_front 376 377 bpy.ops.object.mode_set(mode='EDIT') 378 379 is_odd_scale_bone = False 380 381 # 基幹ボーンのみ作成 382 child_data = [] 383 for data in bone_data: 384 if not data['parent_name']: 385 bone = arm.edit_bones.new(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 386 bone.head, bone.tail = (0, 0, 0), (0, 1, 0) 387 bone.use_deform = False 388 389 #co.x, co.y, co.z = -co.x, co.z, -co.y 390 #rot = compat.mul(rot, mathutils.Quaternion((0, 0, 1), math.radians(90))) 391 #rot.w, rot.x, rot.y, rot.z = -rot.w, -rot.x, rot.z, -rot.y 392 393 #co = data['co' ].copy() 394 #rot = data['rot'].copy() 395 #co.x, co.y, co.z = -co.x, -co.z, co.y 396 #rot.w, rot.x, rot.y, rot.z = -rot.w, -rot.x, -rot.z, rot.y 397 ##rot = compat.mul(rot, mathutils.Quaternion((0, 0, 1), math.radians(-90))) 398 #rot = compat.convert_cm_to_bl_bone_rotation(rot) 399 #mat = compat.mul(mathutils.Matrix.Translation(co), rot.to_matrix().to_4x4()) 400 401 co_mat = mathutils.Matrix.Translation(data['co'].copy() * self.scale) 402 rot = mathutils.Quaternion(data['rot'].copy()) 403 #rot = compat.convert_cm_to_bl_bone_rotation(rot) 404 rot_mat = rot.to_matrix().to_4x4() 405 #rot_mat = compat.convert_cm_to_bl_bone_rotation(rot_mat) 406 mat = compat.mul(co_mat, rot_mat) 407 mat = compat.convert_cm_to_bl_bone_rotation(mat) 408 mat = compat.convert_cm_to_bl_space(mat) 409 #mat = compat.mul(mat, compat.CM_TO_BL_LOCAL_BONE_MAT4) 410 411 412 #fix_mat_scale = mathutils.Matrix.Scale(-1, 4, (1, 0, 0)) 413 #fix_mat_before = mathutils.Euler((math.radians(90), 0, 0), 'XYZ').to_matrix().to_4x4() 414 #fix_mat_after = mathutils.Euler((0, 0, math.radians(90)), 'XYZ').to_matrix().to_4x4() 415 416 #compat.set_bone_matrix(bone, compat.mul4(fix_mat_scale, fix_mat_before, mat, fix_mat_after)) 417 compat.set_bone_matrix(bone, mat) 418 419 420 bone["cm3d2_scl_bone"] = 1 if data['scl'] else 0 421 if 'scale' in data: 422 bone['cm3d2_bone_scale'] = data['scale'] 423 scale = mathutils.Vector(data['scale']) 424 if ( scale - mathutils.Vector((1,1,1)) ).length > 1e-5: 425 is_odd_scale_bone = True 426 self.report(type={'WARNING'}, message=f_tip_("Bone '{bone_name}' has odd scale '{bone_scale}' (odd by {bone_diff})", bone_name=bone.name, bone_scale=scale, bone_diff=( scale - mathutils.Vector((1,1,1)) ).length)) 427 scale *= self.scale * 0.01 428 scale = compat.convert_cm_to_bl_bone_rotation(scale) 429 bone.bbone_x = scale.x 430 bone.bbone_z = scale.z 431 #look = bone.tail - bone.head 432 #look *= scale.y 433 #bone.tail = look + bone.head 434 else: 435 child_data.append(data) 436 context.window_manager.progress_update(1.333) 437 438 # 子ボーンを追加していく 439 while len(child_data): 440 data = child_data.pop(0) 441 parent = arm.edit_bones.get(common.decode_bone_name(data['parent_name'], self.is_convert_bone_weight_names)) 442 if parent: 443 bone = arm.edit_bones.new(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 444 bone.parent = parent 445 bone.head, bone.tail = (0, 0, 0), (0, 1, 0) 446 bone.use_deform = False 447 448 #parent_mats = [] 449 #current_bone = bone 450 #while current_bone: 451 # for b in bone_data: 452 # if common.decode_bone_name(b['name'], self.is_convert_bone_weight_names) == current_bone.name: 453 # local_co = b['co' ].copy() 454 # local_rot = b['rot'].copy() 455 # break 456 # 457 # local_co_mat = mathutils.Matrix.Translation(local_co) 458 # local_rot_mat = local_rot.to_matrix().to_4x4() 459 # parent_mats.append(compat.mul(local_co_mat, local_rot_mat)) 460 # 461 # current_bone = current_bone.parent 462 #parent_mats.reverse() 463 # 464 #mat = mathutils.Matrix() 465 #for local_mat in parent_mats: 466 # mat = compat.mul(mat, local_mat) 467 #mat *= self.scale 468 #mat = compat.convert_cm_to_bl_space(mat) 469 #mat = compat.convert_cm_to_bl_bone_rotation(mat) 470 471 #parent_mat = compat.mul( 472 # mathutils.Matrix.Translation(parent.matrix.to_translation()), 473 # parent.matrix.to_quaternion().to_matrix().to_4x4() 474 #) 475 476 parent_mat = parent.matrix 477 478 local_co = data['co' ].copy() * self.scale 479 local_rot = data['rot'].copy() 480 #local_rot = compat.convert_cm_to_bl_bone_rotation(rot) 481 local_co_mat = mathutils.Matrix.Translation(local_co) 482 local_rot_mat = local_rot.to_matrix().to_4x4() 483 local_mat = compat.mul(local_co_mat, local_rot_mat) 484 local_mat = compat.convert_cm_to_bl_bone_space(local_mat) 485 #local_mat = compat.mul(local_mat, mathutils.Matrix.Diagonal((1,1,1)).to_4x4()) 486 mat = compat.mul(parent_mat, local_mat) 487 mat = compat.convert_cm_to_bl_bone_rotation(mat) 488 489 490 #co_mat = compat.mul( parent.matrix.inverted(), compat.convert_cm_to_bl_local_bone_mat4(local_co_mat) ) 491 #rot_mat = compat.mul( local_rot_mat, compat.CM_TO_BL_LOCAL_BONE_MAT4 ) 492 #mat = compat.ul(co_mat, rot_mat) 493 #local_mat = compat.mul(local_co_mat, local_rot_mat) 494 #local_mat *= self.scale 495 #mat = compat.mul( parent.matrix, compat.convert_cm_to_bl_local_bone(local_mat) ) 496 #mat *= self.scale 497 498 #mat *= self.scale 499 500 #co.x, co.y, co.z = -co.y, co.z, co.x 501 #rot.w, rot.x, rot.y, rot.z = rot.w, rot.y, -rot.z, -rot.x 502 503 #co = data['co' ].copy() * self.scale 504 #rot = data['rot'].copy() 505 #co.x, co.y, co.z = co.z, -co.x, co.y 506 ##co = compat.convert_cm_to_bl_local_bone(co) 507 ##rot.w, rot.x, rot.y, rot.z = rot.w, -rot.z, rot.x, -rot.y 508 ##rot.w, rot.x, rot.y, rot.z = rot.w, -rot.z, rot.x, -rot.y 509 #local_mat = compat.mul(mathutils.Matrix.Translation(co), rot.to_matrix().to_4x4()) 510 #mat = compat.mul( parent.matrix, local_mat ) 511 ##mat *= self.scale 512 513 #fix_mat_scale = mathutils.Matrix.Scale(-1, 4, (1, 0, 0)) 514 #fix_mat_before = mathutils.Euler((math.radians(90), 0, 0), 'XYZ').to_matrix().to_4x4() 515 #fix_mat_after = mathutils.Euler((0, 0, math.radians(90)), 'XYZ').to_matrix().to_4x4() 516 517 #compat.set_bone_matrix(bone, compat.mul4(fix_mat_scale, fix_mat_before, mat, fix_mat_after)) 518 compat.set_bone_matrix(bone, mat) 519 520 bone['cm3d2_scl_bone'] = 1 if data['scl'] else 0 521 if 'scale' in data: 522 bone['cm3d2_bone_scale'] = data['scale'] 523 scale = mathutils.Vector(data['scale']) 524 if ( scale - mathutils.Vector((1,1,1)) ).length > 1e-5: 525 is_odd_scale_bone = True 526 self.report(type={'WARNING'}, message=f_tip_("Bone '{bone_name}' has odd scale '{bone_scale}' (odd by {bone_diff})", bone_name=bone.name, bone_scale=scale, bone_diff=( scale - mathutils.Vector((1,1,1)) ).length)) 527 scale *= self.scale * 0.01 528 bone.bbone_x = scale.x 529 bone.bbone_z = scale.z 530 #bone.bbone_segments = scale.y 531 #look = bone.tail - bone.head 532 #look *= scale.y 533 #bone.tail = look + bone.head 534 else: 535 child_data.append(data) 536 context.window_manager.progress_update(1.666) 537 538 # Configure bones in local bone data 539 is_local_bones_corrupt = False 540 base_bone = arm.edit_bones.get(common.decode_bone_name(model_name2, self.is_convert_bone_weight_names)) 541 base_bone_offset = base_bone.matrix.copy() 542 base_bone_offset = compat.mul(mathutils.Matrix.Scale(-1, 4, (1, 0, 0)), base_bone_offset) 543 base_bone_offset = compat.convert_bl_to_cm_bone_rotation(base_bone_offset) 544 print(base_bone_offset) 545 print(f"base_bone_offset @ I =\n{base_bone_offset @ mathutils.Matrix.Identity(4)}") 546 #base_bone_offset = mathutils.Matrix.Identity(4) # compat.mul(base_bone_mat.inverted(), base_bone_mat) 547 548 def setup_local_bone(bone, mat, isRoot=False): 549 pos = compat.transform_inverse(mat.transposed()).translation 550 mat.row[3] = (0.0, 0.0, 0.0, 1.0) 551 mat.translation = pos 552 mat.translation *= self.scale 553 offset_mat = mat.copy() 554 if not common.is_descendant_of(bone, base_bone): 555 mat = compat.mul(base_bone_offset, mat) 556 #mat.translation = mat.translation + base_bone_offset.translation 557 mat = compat.convert_cm_to_bl_bone_rotation(mat) 558 mat = compat.mul(mathutils.Matrix.Scale(-1, 4, (1, 0, 0)), mat) 559 560 561 # The matrices from the local bone data are more precise rotations, but make sure they aren't corrupted 562 old_pos, old_rot, old_scale = bone.matrix.decompose() 563 compat.set_bone_matrix(bone, mat) 564 new_pos, new_rot, new_scale = bone.matrix.decompose() 565 dif_pos = (new_pos-old_pos).length/self.scale 566 dif_rot = old_rot.rotation_difference(new_rot) 567 if dif_pos > 0.1 or dif_rot.w < .9: 568 print(dif_pos, dif_rot) 569 is_local_bones_corrupt = True 570 #self.report(type={'WARNING'}, message="Found potentially corrupt local bone data, please re-import with \"Use Local Bone Data\" disabled.") 571 return mat 572 573 for data in local_bone_data: 574 if self.is_use_local_bones and data['name'] == model_name2: 575 bone = arm.edit_bones.get(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 576 mat = mathutils.Matrix(data['matrix']) 577 print("Found base bone in local bone data!") 578 #base_bone_offset = compat.mul(compat.transform_inverse(base_bone_offset), setup_local_bone(bone, mat, isRoot=True)) 579 580 581 for data in local_bone_data: 582 bone = arm.edit_bones.get(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 583 bone.use_deform = True 584 if self.is_use_local_bones and not data['name'] == model_name2: 585 mat = mathutils.Matrix(data['matrix']) 586 setup_local_bone(bone, mat) 587 588 589 def distOnRay(pos0, pos1, point): 590 w = point - pos0 591 d = (pos1 - pos0).normalized() 592 return w.dot(d) / d.dot(d) 593 594 # ボーン整頓 595 for bone in arm.edit_bones: 596 if len(bone.children) == 0: 597 if bone.parent: 598 bone.length = bone.parent.length * 0.5 599 else: 600 bone.length = 0.2 * self.scale 601 elif len(bone.children) == 1: 602 co = bone.children[0].head - bone.head 603 bone.length = co.length 604 elif len(bone.children) >= 2: 605 if bone.parent: 606 max_len = 0.0 607 for child_bone in bone.children: 608 if "Pelvis" in bone.name: 609 dist = (child_bone.head - bone.head).length 610 else: 611 dist = distOnRay(bone.head, bone.tail, child_bone.head) 612 if dist > max_len: 613 max_len = dist 614 bone.length = max_len 615 else: 616 bone.length = 0.2 * self.scale 617 for bone in arm.edit_bones: 618 if len(bone.children) == 0: 619 if bone.parent: 620 bone.length = bone.parent.length * 0.5 621 622 # Make sure no bones are length 0, otherwise blender deletes them 623 for bone in arm.edit_bones: 624 min_length = 0.0001 625 if bone.length < min_length: 626 bone.length = min_length 627 628 # 一部ボーン削除 629 if self.is_armature_clean: 630 for bone in arm.edit_bones: 631 for b in local_bone_data: 632 name = common.decode_bone_name(b['name'], self.is_convert_bone_weight_names) 633 if bone.name == name: 634 break 635 else: 636 arm.edit_bones.remove(bone) 637 638 arm.layers[16] = True 639 compat.set_display_type(arm, prefs.bone_display_type) 640 bpy.ops.armature.select_all(action='DESELECT') 641 bpy.ops.object.mode_set(mode='OBJECT') 642 if self.is_custom_bones: 643 print("Set custom bones") 644 for pose_bone in arm_ob.pose.bones: 645 pose_bone.custom_shape = custom_bone_ob 646 context.window_manager.progress_update(2) 647 648 if self.is_mesh: 649 ob, me = self.create_mesh(context, model_name1, vertex_data, face_data) 650 # オブジェクト変形 651 CNV_OT_align_to_cm3d2_base_bone.from_bone_data(ob, bone_data, local_bone_data, base_bone_name=model_name2, scale=self.scale) 652 context.window_manager.progress_update(3) 653 654 self.create_uvs(context, me, vertex_data, extra_uv_uses) 655 context.window_manager.progress_update(4) 656 657 self.create_vertex_groups(context, ob, vertex_data, local_bone_data) 658 context.window_manager.progress_update(5) 659 660 self.create_shapekeys(context, ob, misc_data) 661 context.window_manager.progress_update(6) 662 663 # マテリアル追加 664 progress_count_total = 0.0 665 for data in material_data: 666 progress_count_total += 1 #len(data['data']) 667 self.progress_plus_value = 1.0 / (progress_count_total if progress_count_total > 0.0 else 1.0) 668 self.progress_count = 6.0 669 670 face_seek = 0 671 mates_set = set() 672 override = context.copy() 673 override['object'] = ob 674 prefs = common.preferences() 675 for index, data in enumerate(material_data): 676 print(f_("material count: {num} of {count}", num=index, count=material_count)) 677 if prefs.mate_unread_same_value and data.name in mates_set: 678 continue 679 mates_set.add(data.name) 680 #common.preferences().mate_unread_same_value 681 bpy.ops.object.material_slot_add(override) 682 mate = context.blend_data.materials.new(data.name)#['name1']) 683 #mate['shader1'] = data['name2'] 684 #mate['shader2'] = data['name3'] 685 686 ob.material_slots[-1].material = mate 687 # 面にマテリアル割り当て 688 for i in range(face_seek, face_seek + len(face_data[index])): 689 me.polygons[i].material_index = index 690 face_seek += len(face_data[index]) 691 692 # テクスチャ追加 693 if compat.IS_LEGACY: 694 #self.create_mateprop_old(context, me, texes_set, mate, index, data) 695 cm3d2_data.MaterialHandler.apply_to_old(override, mate, data) 696 common.decorate_material(mate, self.is_decorate, me, index) 697 else: 698 #self.create_mateprop(context, me, texes_set, mate, index, data) 699 cm3d2_data.MaterialHandler.apply_to(override, mate, data) 700 common.decorate_material(mate, self.is_decorate, me, index) 701 common.setup_material(mate) 702 703 ob.active_material_index = 0 704 context.window_manager.progress_update(7) 705 706 # メッシュ整頓 707 pre_mesh_select_mode = context.tool_settings.mesh_select_mode[:] 708 709 # Too buggy on versions before 2.91 so just disable it outright 710 #if self.is_sharp and (compat.IS_LEGACY or bpy.app.version < (2, 91)): 711 # context.tool_settings.mesh_select_mode = (False, True, False) 712 # bpy.ops.object.mode_set(mode='EDIT') 713 # 714 # bpy.ops.mesh.select_non_manifold(extend=False, use_wire=True, use_boundary=True, use_multi_face=False, use_non_contiguous=False, use_verts=False) 715 # for is_comparison, vert in zip(comparison_data, me.vertices): 716 # if is_comparison: 717 # vert.select = False 718 # bpy.ops.mesh.mark_sharp(use_verts=False) 719 # 720 # bpy.ops.object.mode_set(mode='OBJECT') 721 722 can_mark_sharp = not compat.IS_LEGACY and bpy.app.version >= (2, 91) 723 724 if self.is_remove_doubles: 725 context.tool_settings.mesh_select_mode = (True, False, False) 726 bpy.ops.object.mode_set(mode='EDIT') 727 if not self.is_sharp or not can_mark_sharp: 728 bpy.ops.mesh.select_all(action='DESELECT') 729 bpy.ops.object.mode_set(mode='OBJECT') 730 for is_comparison, vert in zip(comparison_data, me.vertices): 731 if is_comparison: 732 vert.select = True 733 bpy.ops.object.mode_set(mode='EDIT') 734 else: 735 bpy.ops.mesh.select_all(action='SELECT') 736 737 if not can_mark_sharp: 738 bpy.ops.mesh.remove_doubles(threshold=0.000001/5 * self.scale) 739 else: 740 bpy.ops.mesh.remove_doubles(threshold=0.000001/5 * self.scale, use_sharp_edge_from_normals=self.is_sharp) 741 bpy.ops.object.mode_set(mode='OBJECT') 742 743 context.tool_settings.mesh_select_mode = pre_mesh_select_mode 744 745 if self.is_seam: 746 bpy.ops.object.mode_set(mode='EDIT') 747 bpy.ops.mesh.select_all(action='SELECT') 748 bpy.ops.uv.select_all(action='SELECT') 749 bpy.ops.uv.seams_from_islands() 750 bpy.ops.object.mode_set(mode='OBJECT') 751 bpy.ops.object.mode_set(mode='EDIT') 752 bpy.ops.mesh.select_all(action='DESELECT') 753 bpy.ops.object.mode_set(mode='OBJECT') 754 755 if self.is_armature: 756 mod = ob.modifiers.new("Armature", 'ARMATURE') 757 mod.object = arm_ob 758 compat.set_active(context, arm_ob) 759 bpy.ops.object.parent_set(type='OBJECT', keep_transform=True) 760 compat.set_active(context, ob) 761 context.window_manager.progress_update(8) 762 763 # マテリアル情報のテキスト埋め込み 764 if self.is_mate_data_text: 765 for index, data in enumerate(material_data): 766 txt_name = "Material:" + str(index) 767 if txt_name in context.blend_data.texts: 768 txt = context.blend_data.texts[txt_name] 769 txt.clear() 770 else: 771 txt = context.blend_data.texts.new(txt_name) 772 txt.write(data.to_text()) 773 774 # txt.write("1000" + "\n") 775 # txt.write(data['name1'].lower() + "\n") 776 # txt.write(data['name1'] + "\n") 777 # txt.write(data['name2'] + "\n") 778 # txt.write(data['name3'] + "\n") 779 # txt.write("\n") 780 # for tex_data in data['data']: 781 # txt.write(tex_data['type'] + "\n") 782 # if tex_data['type'] == 'tex': 783 # txt.write("\t" + tex_data['name'] + "\n") 784 # txt.write("\t" + tex_data['type2'] + "\n") 785 # if tex_data['type2'] == 'tex2d': 786 # txt.write("\t" + tex_data['name2'] + "\n") 787 # txt.write("\t" + tex_data['path'] + "\n") 788 # map_list = tex_data['tex_map'] 789 # tex_map = " ".join([str(map_list[0]), str(map_list[1]), str(map_list[2]), str(map_list[3])]) 790 # txt.write("\t" + tex_map + "\n") 791 # elif tex_data['type'] == 'col': 792 # txt.write("\t" + tex_data['name'] + "\n") 793 # col = " ".join([str(tex_data['color'][0]), str(tex_data['color'][1]), str(tex_data['color'][2]), str(tex_data['color'][3])]) 794 # txt.write("\t" + col + "\n") 795 # elif tex_data['type'] == 'f': 796 # txt.write("\t" + tex_data['name'] + "\n") 797 # txt.write("\t" + str(tex_data['float']) + "\n") 798 # txt.current_line_index = 0 799 context.window_manager.progress_update(9) 800 801 # ボーン情報のテキスト埋め込み 802 if self.is_bone_data_text: 803 if "BoneData" in context.blend_data.texts: 804 txt = context.blend_data.texts["BoneData"] 805 txt.clear() 806 else: 807 txt = context.blend_data.texts.new("BoneData") 808 for i, data in enumerate(bone_data): 809 s = ",".join([data['name'], str(data['scl']), ""]) 810 parent_index = data['parent_index'] 811 if -1 < parent_index: 812 s += bone_data[parent_index]['name'] + "," 813 else: 814 s += "None" + "," 815 s += " ".join([str(data['co'][0]), str(data['co'][1]), str(data['co'][2])]) + "," 816 s += " ".join([str(data['rot'][0]), str(data['rot'][1]), str(data['rot'][2]), str(data['rot'][3])]) 817 if model_ver >= 2001: 818 if 'scale' in data: 819 s += ",1," + " ".join(map(str, data['scale'])) 820 else: 821 s += ",0" 822 823 if self.is_bone_data_text: 824 txt.write(s + "\n") 825 if self.is_mesh and self.is_bone_data_obj_property: 826 ob["BoneData:" + str(i)] = s 827 if self.is_armature and self.is_bone_data_arm_property: 828 arm["BoneData:" + str(i)] = s 829 if self.is_bone_data_text: 830 txt['BaseBone'] = model_name2 831 txt.current_line_index = 0 832 context.window_manager.progress_update(10) 833 834 # ローカルボーン情報のテキスト埋め込み 835 if self.is_bone_data_text: 836 if "LocalBoneData" in context.blend_data.texts: 837 txt = context.blend_data.texts["LocalBoneData"] 838 txt.clear() 839 else: 840 txt = context.blend_data.texts.new("LocalBoneData") 841 for i, data in enumerate(local_bone_data): 842 s = data['name'] + "," 843 844 mat_list = list(data['matrix'][0]) 845 mat_list.extend(list(data['matrix'][1])) 846 mat_list.extend(list(data['matrix'][2])) 847 mat_list.extend(list(data['matrix'][3])) 848 for j, f in enumerate(mat_list): 849 mat_list[j] = str(f) 850 s += " ".join(mat_list) 851 852 if self.is_bone_data_text: 853 txt.write(s + "\n") 854 if self.is_mesh and self.is_bone_data_obj_property: 855 ob["LocalBoneData:" + str(i)] = s 856 if self.is_armature and self.is_bone_data_arm_property: 857 arm["LocalBoneData:" + str(i)] = s 858 if self.is_bone_data_text: 859 txt['BaseBone'] = model_name2 860 txt.current_line_index = 0 861 862 if self.is_mesh and self.is_bone_data_obj_property: 863 ob['BaseBone'] = model_name2 864 if model_ver >= 1000: 865 ob['ModelVersion'] = model_ver 866 if self.is_armature and self.is_bone_data_arm_property: 867 arm['BaseBone'] = model_name2 868 if model_ver >= 1000: 869 arm['ModelVersion'] = model_ver 870 context.window_manager.progress_end() 871 872 require_time = time.time() - start_time 873 filesize = os.path.getsize(self.filepath) 874 filesize_str = "バイト" 875 if 1024 * 1024 < filesize: 876 filesize = filesize / (1024 * 1024.0) 877 filesize_str = "MB" 878 elif 1024 < filesize: 879 filesize = filesize / 1024.0 880 filesize_str = "KB" 881 self.report(type={'INFO'}, message=f_tip_("modelのインポートが完了しました ({} {}/ {:.2f} 秒)", filesize, filesize_str, require_time)) 882 883 if is_odd_scale_bone: 884 self.report(type={'WARNING'}, message="Found bone with a scale not equal to 1.") 885 if is_local_bones_corrupt: 886 self.report(type={'ERROR'}, message="Found potentially corrupt local bone data, please re-import with \"Use Local Bone Data\" disabled.") 887 return {'FINISHED'} 888 889 def create_mesh(self, context, model_name1, vertex_data, face_data) -> (bpy.types.Object, bpy.types.Mesh): 890 # メッシュ作成 891 me = context.blend_data.meshes.new(model_name1) 892 verts, faces = [], [] 893 for data in vertex_data: 894 #co = list(data['co'][:]) 895 #co[0] = -co[0] 896 #co[0] *= self.scale 897 #co[1] *= self.scale 898 #co[2] *= self.scale 899 co = compat.convert_cm_to_bl_space( mathutils.Vector(data['co']) * self.scale ) 900 #co = mathutils.Vector(data['co']) * self.scale 901 verts.append(co) 902 context.window_manager.progress_update(2.25) 903 for data in face_data: 904 faces.extend(data) 905 context.window_manager.progress_update(2.5) 906 me.from_pydata(verts, [], faces) 907 908 # オブジェクト化 909 ob = context.blend_data.objects.new(model_name1, me) 910 ob.rotation_mode = 'QUATERNION' 911 compat.link(context.scene, ob) 912 compat.set_select(ob, True) 913 compat.set_active(context, ob) 914 bpy.ops.object.shade_smooth() 915 context.window_manager.progress_update(2.75) 916 917 # Custom Split Normals 918 #normals_color = me.vertex_colors.new(name=f"Basis_normals", do_init=False) or me.vertex_colors[-1] 919 #for vert_index, vert in enumerate(vertex_data): 920 # no = compat.convert_cm_to_bl_space( mathutils.Vector(vert['normal']) ) #mathutils.Vector(vert['normal']) * mathutils.Vector((-1,1,1)) # 921 # no.normalize() 922 # print(no) 923 # for loop_index in vert_loops[vert_index]: 924 # #normals[loop_index] = no 925 # normals_color.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1) 926 # *no, #*(no * 0.5 + mathutils.Vector([0.5]*3)), 927 # 1, 928 # ) 929 #me.normals_split_custom_set(normals) 930 me.normals_split_custom_set_from_vertices( 931 tuple( 932 compat.convert_cm_to_bl_space( mathutils.Vector(vert['normal']) ) 933 for vert in vertex_data 934 ) 935 ) 936 me.use_auto_smooth = True 937 938 return ob, me 939 940 def create_vertex_groups(self, context, ob, vertex_data, local_bone_data): 941 # 頂点グループ作成 942 for data in local_bone_data: 943 ob.vertex_groups.new(name=common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 944 context.window_manager.progress_update(4.333) 945 946 for vert_index, data in enumerate(vertex_data): 947 for weight in data['weights']: 948 if 0.0 < weight['value']: 949 vertex_group = ob.vertex_groups[common.decode_bone_name(weight['name'], self.is_convert_bone_weight_names)] 950 vertex_group.add([vert_index], weight['value'], 'REPLACE') 951 context.window_manager.progress_update(4.666) 952 953 if self.is_vertex_group_sort: 954 bpy.ops.object.vertex_group_sort(sort_type='NAME') 955 956 if self.is_remove_empty_vertex_group: 957 for vg in ob.vertex_groups[:]: 958 for vert in ob.data.vertices: 959 for group in vert.groups: 960 if group.group == vg.index: 961 if 0.0 < group.weight: 962 break 963 else: # if for-loop didn't break 964 continue 965 break 966 else: # if for-loop didn't break 967 ob.vertex_groups.remove(vg) 968 969 ob.vertex_groups.active_index = 0 970 971 def create_uvs(self, context, me, vertex_data, extra_uv_uses): 972 # UV作成 973 bm = bmesh.new() 974 bm.from_mesh(me) 975 bm.loops.layers.uv.new(f_data_("MainUV")) 976 for i, used in enumerate(extra_uv_uses): 977 if used: 978 bm.loops.layers.uv.new(f_data_("ExtraUV{num}", num=i)) 979 for face in bm.faces: 980 for loop in face.loops: 981 loop[bm.loops.layers.uv[0]].uv = vertex_data[loop.vert.index]['uv'] 982 for extra_uv_index, extra_uv in enumerate(vertex_data[loop.vert.index]['extra_uvs']): 983 loop[bm.loops.layers.uv[extra_uv_index+1]].uv = extra_uv 984 bm.to_mesh(me) 985 bm.free() 986 987 def create_shapekeys(self, context, ob, misc_data): 988 # モーフ追加 989 me = ob.data 990 991 is_use_attributes = (not compat.IS_LEGACY and bpy.app.version >= (2,92)) 992 is_fast_create = (not compat.IS_LEGACY and bpy.app.version >= (3,2)) 993 994 #if not is_fast_create: 995 # bpy.ops.object.mode_set(mode='VERTEX_PAINT') 996 # prev_brush_color = context.tool_settings.vertex_paint.brush.color 997 998 vert_loops = dict() 999 for loop_index, loop in enumerate(me.loops): 1000 vert_loops.setdefault(loop.vertex_index, list()).append(loop_index) 1001 1002 def fill_color_layer(layer, color): 1003 import numpy as np 1004 color_np = np.array(color, dtype=float) 1005 color_values = np.broadcast_to(color_np, (len(me.loops), len(color_np))) 1006 layer.data.foreach_set('color', color_values.ravel()) 1007 1008 def create_normals_color(name): 1009 default_color = (0.5, 0.5, 0.5, 1.0) 1010 1011 #if is_fast_create: 1012 # bpy.ops.geometry.color_attribute_add(name=name, domain='CORNER', data_type='FLOAT_COLOR', color=default_color) 1013 # return me.attributes.active 1014 1015 if is_use_attributes: 1016 normals_color = me.attributes.new(name, 'FLOAT_COLOR', 'CORNER') 1017 else: 1018 normals_color = me.vertex_colors.new(name=name, do_init=False) or me.vertex_colors[-1] 1019 1020 fill_color_layer(normals_color, default_color) 1021 1022 return normals_color 1023 1024 def create_unknown_color(data): 1025 unknown_color = None 1026 if len(data['data']) and data['data'][0]['color']: 1027 if is_use_attributes: 1028 unknown_color = me.attributes.new(f"{data['name']}_unknown", 'FLOAT_COLOR', 'CORNER') 1029 else: 1030 unknown_color = me.vertex_colors.new(name=f"{data['name']}_unknown", do_init=False) or me.vertex_colors[-1] 1031 return unknown_color 1032 1033 def set_shape_key_data(shape_key, normals_color, unknown_color): 1034 for vert in data['data']: 1035 vert_index = vert['index'] 1036 co = compat.convert_cm_to_bl_space( mathutils.Vector(vert['co']) * self.scale ) 1037 no = compat.convert_cm_to_bl_space( mathutils.Vector(vert['normal'])) 1038 shape_key.data[vert_index].co = shape_key.data[vert_index].co + co 1039 1040 write_vertex_colors(vert, no, normals_color, unknown_color) 1041 1042 def write_vertex_colors(vert, no, normals_color, unknown_color): 1043 for loop_index in vert_loops[vert['index']]: 1044 normals_color.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1) 1045 no[0] * 0.5 + 0.5, 1046 no[1] * 0.5 + 0.5, 1047 no[2] * 0.5 + 0.5, 1048 1, 1049 ) 1050 if not vert['color']: 1051 continue 1052 unknown_color.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1) 1053 vert['color'][0] * 0.5 * vert['color'][3] + 0.5, 1054 vert['color'][1] * 0.5 * vert['color'][3] + 0.5, 1055 vert['color'][2] * 0.5 * vert['color'][3] + 0.5, 1056 1, 1057 ) 1058 1059 morph_count = -1 1060 for data in misc_data: 1061 if not data['type'] == 'morph': 1062 continue 1063 1064 morph_count += 1 1065 1066 if morph_count == 0: 1067 bpy.ops.object.shape_key_add(from_mix=False) 1068 me.shape_keys.name = ob.name 1069 shape_key = ob.shape_key_add(name=data['name'], from_mix=False) 1070 1071 normals_color = create_normals_color(f"{data['name']}_delta_normals") 1072 unknown_color = create_unknown_color(data) 1073 set_shape_key_data(shape_key, normals_color, unknown_color) 1074 1075 1076 def create_mateprop_old(self, context, me, tex_set, mate, mate_idx, data: list): 1077 # create_matepropとの違いは、slot_indexの有無、nodeの接続・配置処理のみ 1078 1079 prefs = common.preferences() 1080 # テクスチャ追加 1081 slot_index = 0 1082 for tex_data in data['data']: 1083 if prefs.mate_unread_same_value: 1084 if tex_data['name'] in tex_set: 1085 continue 1086 tex_set.add(tex_data['name']) 1087 1088 node_name = tex_data['name'] 1089 if tex_data['type'] == 'tex': 1090 path = tex_data['path'] 1091 tex_map_data = tex_data['tex_map'] 1092 common.create_tex(context, mate, node_name, tex_data['name2'], path, path, tex_map_data, prefs.is_replace_cm3d2_tex, slot_index) 1093 1094 elif tex_data['type'] == 'col': 1095 col = tex_data['color'] 1096 common.create_col(context, mate, node_name, col, slot_index) 1097 1098 elif tex_data['type'] == 'f': 1099 f = tex_data['float'] 1100 common.create_f(context, mate, node_name, f, slot_index) 1101 1102 slot_index += 1 1103 1104 self.progress(context) 1105 1106 def create_mateprop(self, context, me, tex_set, mate, mate_idx, data: list): 1107 if mate.use_nodes is False: 1108 mate.use_nodes = True 1109 1110 nodes = mate.node_tree.nodes 1111 prefs = common.preferences() 1112 1113 for prop_data in data['data']: 1114 if prefs.mate_unread_same_value: 1115 if prop_data['name'] in tex_set: 1116 continue 1117 tex_set.add(prop_data['name']) 1118 1119 if prop_data['type'] == 'tex': # テクスチャ追加 1120 prop_name = prop_data['name'] 1121 if prop_data['type2'] == 'tex2d': 1122 tex_name = prop_data['name2'] 1123 cm3d2path = prop_data['path'] 1124 tex_map = prop_data['tex_map'] 1125 tex = common.create_tex(context, mate, prop_name, tex_name, cm3d2path, cm3d2path, tex_map) 1126 1127 if prop_data['type2'] == 'tex2d': 1128 mapping = prop_data['tex_map'] 1129 tex_map = tex.texture_mapping 1130 tex_map.translation[0] = mapping[0] 1131 tex_map.translation[1] = mapping[1] 1132 tex_map.scale[0] = mapping[2] 1133 tex_map.scale[1] = mapping[3] 1134 1135 # ファイルの実体を割り当て 1136 if prefs.is_replace_cm3d2_tex: 1137 img = tex.image 1138 # col = mate.node_tree.nodes.new(type='ShaderNodeAttribute') 1139 # tex.image = bpy.data.images.load("C:\\path\\to\\im.jpg") 1140 replaced = common.replace_cm3d2_tex(img, self.texpath_dict, reload_path=False) 1141 if compat.IS_LEGACY and replaced and prop_name == '_MainTex': 1142 for face in me.polygons: 1143 if face.material_index == mate_idx: 1144 me.uv_textures.active.data[face.index].image = img 1145 else: 1146 common.create_tex(context, mate, prop_name) 1147 1148 elif prop_data['type'] == 'col': 1149 col = nodes.new(type='ShaderNodeRGB') 1150 col.name = col.label = prop_data['name'] 1151 # val.type = 'RGB' 1152 col.outputs[0].default_value = prop_data['color'][:4] 1153 1154 # mate.node_tree.links.new(bsdf.inputs['xxx'], val.outputs['Color']) 1155 # mate.node_tree.nodes.active = col 1156 1157 # slot = mate.texture_slots.create(tex_index) 1158 # mate.use_textures[tex_index] = False 1159 # slot.diffuse_color_factor = tex_data['color'][3] 1160 # slot.use_rgb_to_intensity = True 1161 # tex = context.blend_data.textures.new(tex_data['name'], 'BLEND') 1162 # slot.texture = tex 1163 1164 elif prop_data['type'] == 'f': 1165 val = nodes.new(type='ShaderNodeValue') 1166 val.name = prop_data['name'] 1167 val.label = prop_data['name'] 1168 # val.type = 'VALUE' 1169 # mate.node_tree.links.new(bsdf.inputs['xxx'], val.outputs['Value']) 1170 1171 val.outputs[0].default_value = prop_data['float'] 1172 1173 self.progress(context) 1174 1175 cm3d2_data.align_nodes(mate) 1176 1177 def progress(self, context): 1178 self.progress_count += self.progress_plus_value 1179 context.window_manager.progress_update(self.progress_count) 1180 1181 1182# メニューを登録する関数 1183def menu_func(self, context): 1184 self.layout.operator(CNV_OT_import_cm3d2_model.bl_idname, icon_value=common.kiss_icon())
@compat.BlRegister()
class
CNV_OT_import_cm3d2_model20@compat.BlRegister() 21#@bpy_extras.io_utils.orientation_helper(axis_forward='-Z', axis_up='Y') 22class CNV_OT_import_cm3d2_model(bpy.types.Operator, bpy_extras.io_utils.ImportHelper): 23 bl_idname = 'import_mesh.import_cm3d2_model' 24 bl_label = "CM3D2モデル (.model)" 25 bl_description = "カスタムメイド3D2のmodelファイルを読み込みます" 26 bl_options = {'REGISTER'} 27 28 filepath = bpy.props.StringProperty(subtype='FILE_PATH') 29 filename_ext = ".model" 30 filter_glob = bpy.props.StringProperty(default="*.model", options={'HIDDEN'}) 31 32 scale = bpy.props.FloatProperty(name="倍率", default=5, min=0.1, max=100, soft_min=0.1, soft_max=100, step=100, precision=1, description="インポート時のメッシュ等の拡大率です") 33 34 is_mesh = bpy.props.BoolProperty(name="メッシュ生成", default=True, description="ポリゴンを読み込みます、大抵の場合オンでOKです") 35 is_remove_doubles = bpy.props.BoolProperty(name="重複頂点を結合", default=True, description="UVの切れ目でポリゴンが分かれている仕様なので、インポート時にくっつけます") 36 is_seam = bpy.props.BoolProperty(name="シームをつける", default=True, description="UVの切れ目にシームをつけます") 37 is_sharp = bpy.props.BoolProperty(name="Mark Sharp", default=True, description="This will mark removed doubles on your mesh as sharp (or all free edges if not removing doubles).") 38 39 is_convert_bone_weight_names = bpy.props.BoolProperty(name="頂点グループ名をBlender用に変換", default=False, description="全ての頂点グループ名をBlenderの左右対称編集で使えるように変換してから読み込みます") 40 is_vertex_group_sort = bpy.props.BoolProperty(name="頂点グループを名前順ソート", default=True, description="頂点グループを名前順でソートします") 41 is_remove_empty_vertex_group = bpy.props.BoolProperty(name="割り当てのない頂点グループを削除", default=True, description="全ての頂点に割り当てのない頂点グループを削除します") 42 43 reload_tex_cache = bpy.props.BoolProperty(name="テクスチャキャッシュを再構成", default=False, description="texファイルを探す際、キャッシュを再構成します") 44 is_decorate = bpy.props.BoolProperty(name="種類に合わせてマテリアルを装飾", default=True) 45 is_mate_data_text = bpy.props.BoolProperty(name="テキストにマテリアル情報埋め込み", default=True, description="シェーダー情報をテキストに埋め込みます") 46 47 is_armature = bpy.props.BoolProperty(name="アーマチュア生成", default=True, description="ウェイトを編集する時に役立つアーマチュアを読み込みます") 48 is_armature_clean = bpy.props.BoolProperty(name="不要なボーンを削除", default=False, description="ウェイトが無いボーンを削除します") 49 is_custom_bones = bpy.props.BoolProperty(name="Use Custom Bones", default=False, description="Use the currently selected object for custom bone shapes.") 50 is_use_local_bones = bpy.props.BoolProperty(name="Use Local Bones", default=True, description="Use the Local Bone Data for orientation (more accurate)") 51 52 is_bone_data_text = bpy.props.BoolProperty(name="テキスト", default=True, description="ボーン情報をテキストとして読み込みます") 53 is_bone_data_obj_property = bpy.props.BoolProperty(name="オブジェクトのカスタムプロパティ", default=True, description="メッシュオブジェクトのカスタムプロパティにボーン情報を埋め込みます") 54 is_bone_data_arm_property = bpy.props.BoolProperty(name="アーマチュアのカスタムプロパティ", default=True, description="アーマチュアデータのカスタムプロパティにボーン情報を埋め込みます") 55 texpath_dict = None 56 57 @classmethod 58 def poll(cls, context): 59 return True 60 61 def invoke(self, context, event): 62 prefs = common.preferences() 63 if prefs.model_default_path: 64 self.filepath = common.default_cm3d2_dir(prefs.model_default_path, None, "model") 65 else: 66 self.filepath = common.default_cm3d2_dir(prefs.model_import_path, None, "model") 67 self.scale = prefs.scale 68 self.is_convert_bone_weight_names = prefs.is_convert_bone_weight_names 69 if compat.IS_LEGACY or bpy.app.version < (2, 91): 70 self.is_sharp = False 71 context.window_manager.fileselect_add(self) 72 return {'RUNNING_MODAL'} 73 74 def draw(self, context): 75 prefs = common.preferences() 76 self.layout.prop(self, 'scale') 77 78 box = self.layout.box() 79 box.prop(self, 'is_mesh', icon='MESH_DATA') 80 81 sub_box = box.box() 82 sub_box.enabled = self.is_mesh 83 sub_box.label(text="メッシュ") 84 sub_box.prop(self, 'is_remove_doubles', icon='STICKY_UVS_VERT') 85 sub_box.prop(self, 'is_seam' , icon=compat.icon('UV_EDGESEL')) 86 if not compat.IS_LEGACY and bpy.app.version >= (2, 91): 87 sub_box.prop(self, 'is_sharp', icon=compat.icon('EDGESEL')) 88 89 sub_box = box.box() 90 sub_box.enabled = self.is_mesh 91 sub_box.label(text="頂点グループ") 92 sub_box.prop(self, 'is_vertex_group_sort', icon='SORTALPHA') 93 sub_box.prop(self, 'is_remove_empty_vertex_group', icon='DISCLOSURE_TRI_DOWN') 94 sub_box.prop(self, 'is_convert_bone_weight_names', icon='BLENDER') 95 96 sub_box = box.box() 97 sub_box.enabled = self.is_mesh 98 sub_box.label(text="マテリアル") 99 sub_box.prop(prefs, 'is_replace_cm3d2_tex', icon='BORDERMOVE') 100 sub_box.prop(self, 'reload_tex_cache', icon='FILE_REFRESH') 101 if compat.IS_LEGACY: 102 sub_box.prop(self, 'is_decorate', icon=compat.icon('SHADING_TEXTURE')) 103 sub_box.prop(self, 'is_mate_data_text', icon='TEXT') 104 105 box = self.layout.box() 106 box.prop(self, 'is_armature', icon='ARMATURE_DATA') 107 108 sub_box = box.box() 109 sub_box.label(text="アーマチュア") 110 sub_box.prop(self , 'is_use_local_bones' , icon=compat.icon('GROUP_BONE'), text="Use Local Bone Data") 111 sub_box.prop(self , 'is_armature_clean' , icon=compat.icon('X' )) 112 sub_box.prop(self , 'is_convert_bone_weight_names', icon=compat.icon('BLENDER' ), text="ボーン名をBlender用に変換") 113 sub_box.prop(prefs, 'show_bone_in_front' , icon=compat.icon('HIDE_OFF' ), text="Show Bones in Front") 114 row = sub_box.row() 115 row.prop (self , 'is_custom_bones' , icon=compat.icon('BONE_DATA' ), text="Use Selected as Bone Shape" ) 116 row.enabled = bool(context.object) 117 118 box = self.layout.box() 119 box.label(text="ボーン情報埋め込み場所") 120 box.prop(self, 'is_bone_data_text', icon='TEXT') 121 box.prop(self, 'is_bone_data_obj_property', icon='OBJECT_DATA') 122 box.prop(self, 'is_bone_data_arm_property', icon='ARMATURE_DATA') 123 124 def execute(self, context): 125 start_time = time.time() 126 127 prefs = common.preferences() 128 prefs.model_import_path = self.filepath 129 prefs.scale = self.scale 130 context.window_manager.progress_begin(0, 10) 131 context.window_manager.progress_update(0) 132 133 custom_bone_ob = context.active_object 134 if not custom_bone_ob: 135 self.is_custom_bones = False 136 137 #global_matrix = bpy_extras.io_utils.axis_conversion(from_forward=self.axis_forward, from_up=self.axis_up).to_4x4() 138 139 try: 140 reader = open(self.filepath, 'rb') 141 except: 142 self.report(type={'ERROR'}, message=f_tip_("ファイルを開くのに失敗しました、アクセス不可かファイルが存在しません。file={}", self.filepath)) 143 return {'CANCELLED'} 144 145 self.texpath_dict = common.get_texpath_dict(reload=self.reload_tex_cache) 146 147 with reader: 148 # ヘッダー 149 ext = None 150 try: # luvoid : utf-8 decoding could possibly throw an error here 151 ext = common.read_str(reader) 152 except: 153 ext = False 154 if ext != 'CM3D2_MESH': 155 self.report(type={'ERROR'}, message="これはカスタムメイド3D2のモデルファイルではありません") 156 return {'CANCELLED'} 157 model_ver = struct.unpack('<i', reader.read(4))[0] 158 self.report(type={'INFO'}, message=f_tip_("Model Version = {version}", version=model_ver)) 159 context.window_manager.progress_update(0.1) 160 161 try: 162 # 名前群を取得 163 model_name1 = common.read_str(reader) 164 model_name2 = common.read_str(reader) 165 context.window_manager.progress_update(0.2) 166 167 # ボーン情報読み込み 168 bone_data = [] 169 bone_count = struct.unpack('<i', reader.read(4))[0] 170 for i in range(bone_count): 171 name = common.read_str(reader) 172 scl = struct.unpack('<B', reader.read(1))[0] 173 bone_data.append({'name': name, 'scl': scl}) 174 175 for i in range(bone_count): 176 parent_index = struct.unpack('<i', reader.read(4))[0] 177 parent_name = None 178 if parent_index != -1: 179 parent_name = bone_data[parent_index]['name'] 180 bone_data[i]['parent_index'] = parent_index 181 bone_data[i]['parent_name'] = parent_name 182 183 for i in range(bone_count): 184 x, y, z = struct.unpack('<3f', reader.read(3*4)) 185 bone_data[i]['co'] = mathutils.Vector((x, y, z)) 186 187 x, y, z = struct.unpack('<3f', reader.read(3*4)) 188 w = struct.unpack('<f', reader.read(4))[0] 189 bone_data[i]['rot'] = mathutils.Quaternion((w, x, y, z)) 190 if model_ver >= 2001: 191 use_scale = struct.unpack('<B', reader.read(1))[0] 192 if use_scale: 193 print(bone_data[i]['name'],"has scale data!") 194 scale_x, scale_y, scale_z = struct.unpack('<3f', reader.read(3*4)) 195 bone_data[i]['scale'] = [scale_x, scale_y, scale_z] 196 197 context.window_manager.progress_update(0.3) 198 199 print(f_("Reading vertex, mesh, and local bone count at 0x{num:02X}", num=reader.tell())) 200 vertex_count, mesh_count, local_bone_count = struct.unpack('<3i', reader.read(3*4)) 201 202 # ローカルボーン情報読み込み 203 local_bone_data = [] 204 for i in range(local_bone_count): 205 local_bone_data.append({'name': common.read_str(reader)}) 206 207 for i in range(local_bone_count): 208 row0 = struct.unpack('<4f', reader.read(4 * 4)) 209 row1 = struct.unpack('<4f', reader.read(4 * 4)) 210 row2 = struct.unpack('<4f', reader.read(4 * 4)) 211 row3 = struct.unpack('<4f', reader.read(4 * 4)) 212 local_bone_data[i]['matrix'] = mathutils.Matrix([row0, row1, row2, row3]) 213 context.window_manager.progress_update(0.4) 214 215 # 頂点情報読み込み 216 vertex_data = [] 217 print(f_("Reading vertex data at 0x{num:02X}", num=reader.tell())) 218 extra_uv_uses = [False] * 7 219 if model_ver >= 2102: # CR Edit Mode 220 extra_uv_uses = struct.unpack('<7?', reader.read(7)) 221 print(f_("extra_uv_uses = {boollist}", boollist=extra_uv_uses)) 222 for i in range(vertex_count): 223 co = struct.unpack('<3f', reader.read(3 * 4)) 224 no = struct.unpack('<3f', reader.read(3 * 4)) 225 uv = struct.unpack('<2f', reader.read(2 * 4)) 226 extra_uvs = [] # CR Edit 227 for i, used in enumerate(extra_uv_uses): 228 if used: 229 extra_uvs.append(struct.unpack('<2f', reader.read(2 * 4))) 230 vertex_data.append({'co': co, 'normal': no, 'uv': uv, 'extra_uvs': extra_uvs}) 231 if self.is_remove_doubles: 232 comparison_data = list(hash(repr(v['co']) + " " + repr(v['normal'])) for v in vertex_data) 233 comparison_counter = Counter(comparison_data) 234 comparison_data = list((comparison_counter[h] > 1) for h in comparison_data) 235 del comparison_counter 236 print(f_("Reading unknown count at 0x{num:02X}", num=reader.tell())) 237 unknown_count = struct.unpack('<i', reader.read(4))[0] 238 for i in range(unknown_count): 239 struct.unpack('<4f', reader.read(4 * 4)) 240 for i in range(vertex_count): 241 indexes = struct.unpack('<4H', reader.read(4 * 2)) 242 values = struct.unpack('<4f', reader.read(4 * 4)) 243 vertex_data[i]['weights'] = list({ 244 'index': index, 245 'value': value, 246 'name': local_bone_data[index]['name'], 247 } for index, value in zip(indexes, values)) 248 context.window_manager.progress_update(0.5) 249 # 面情報読み込み 250 face_data = [] 251 for i in range(mesh_count): 252 face_count = int(struct.unpack('<i', reader.read(4))[0] / 3) 253 datum = [tuple(reversed(struct.unpack('<3H', reader.read(3 * 2)))) for j in range(face_count)] 254 face_data.append(datum) 255 context.window_manager.progress_update(0.6) 256 257 # マテリアル情報読み込み 258 # TODO MaterialHandlerに変更 259 material_data = [] 260 material_count = struct.unpack('<i', reader.read(4))[0] 261 for i in range(material_count): 262 print(f_("mate count: {num} of {count} @ 0x{pos:02X}", num=i, count=material_count, pos=reader.tell())) 263 data = cm3d2_data.MaterialHandler.read(reader, read_header=False, version=model_ver) 264 data.name1 = data.name.lower() 265 material_data.append(data) 266 267 # name1 = common.read_str(reader) 268 # name2 = common.read_str(reader) 269 # name3 = common.read_str(reader) 270 # data_list = [] 271 # material_data.append({'name1': name1, 'name2': name2, 'name3': name3, 'data': data_list}) 272 # while True: 273 # data_type = common.read_str(reader) 274 # if data_type == 'tex': 275 # data_item = {'type': data_type} 276 # data_list.append(data_item) 277 # data_item['name'] = common.read_str(reader) 278 # data_item['type2'] = common.read_str(reader) 279 # if data_item['type2'] == 'tex2d': 280 # data_item['name2'] = common.read_str(reader) 281 # data_item['path'] = common.read_str(reader) 282 # data_item['tex_map'] = struct.unpack('<4f', reader.read(4*4)) 283 # elif data_type == 'col': 284 # name = common.read_str(reader) 285 # col = struct.unpack('<4f', reader.read(4*4)) 286 # data_list.append({'type': data_type, 'name': name, 'color': col}) 287 # elif data_type == 'f': 288 # name = common.read_str(reader) 289 # fval = struct.unpack('<f', reader.read(4))[0] 290 # data_list.append({'type': data_type, 'name': name, 'float': fval}) 291 # else: 292 # break 293 294 context.window_manager.progress_update(0.8) 295 296 # その他情報読み込み 297 misc_data = [] 298 while True: 299 #print(f_("Reading data_type at 0x{num:02X}", num=reader.tell())) 300 data_type = common.read_str(reader) 301 if data_type == 'morph': 302 misc_item = {'type': data_type} 303 misc_data.append(misc_item) 304 misc_item['name'] = common.read_str(reader) 305 misc_item['data'] = data_list = [] 306 morph_vert_count = struct.unpack('<i', reader.read(4))[0] 307 morph_extra_uvs = False 308 if model_ver >= 2102: # CR Edit Mode 309 morph_extra_uvs = struct.unpack('<?', reader.read(1))[0] 310 misc_item['uvs'] = [] 311 print(f_("{morph}.morph_extra_uvs @ 0x{pos:02X} = {bool}", morph=misc_item['name'], bool=morph_extra_uvs, pos=reader.tell()-1)) 312 for i in range(morph_vert_count): 313 index = struct.unpack('<H', reader.read(2))[0] 314 co = mathutils.Vector(struct.unpack('<3f', reader.read(3 * 4))) 315 normal = struct.unpack('<3f', reader.read(3 * 4)) 316 extra_uvs = () # CR Edit 317 if morph_extra_uvs: 318 extra_uvs = struct.unpack('<4f', reader.read(4 * 4)) 319 data_list.append({'index': index, 'co': co, 'normal': normal, 'color': extra_uvs}) 320 else: 321 break 322 323 except UnicodeDecodeError as e: 324 msg = [ 325 f_tip_("Error reading file at byte 0x{num:02X}", num=reader.tell()-len(e.object)) + "\n", 326 str(e) + "\n", 327 *traceback.format_tb(e.__traceback__) 328 ] 329 self.report(type={'ERROR'}, message="".join(reversed(msg))[0:-1]) 330 print("".join(msg)) 331 return {'CANCELLED'} 332 333 except struct.error as e: 334 msg = [ 335 f_tip_("Error reading file at byte 0x{num:02X}", num=reader.tell()) + "\n", 336 str(e) + "\n", 337 *traceback.format_tb(e.__traceback__) 338 ] 339 self.report(type={'ERROR'}, message="".join(reversed(msg))[0:-1]) 340 print("".join(msg)) 341 return {'CANCELLED'} 342 343 except common.CM3D2ImportException as e: 344 msg = [ 345 f_tip_("Error reading file at byte 0x{num:02X}", num=reader.tell()) + "\n", 346 str(e) + "\n", 347 *traceback.format_tb(e.__traceback__) 348 ] 349 self.report(type={'ERROR'}, message="".join(reversed(msg))[0:-1]) 350 print("".join(msg)) 351 return {'CANCELLED'} 352 353 context.window_manager.progress_update(1) 354 355 try: 356 bpy.ops.object.mode_set(mode='OBJECT') 357 except RuntimeError: 358 pass 359 bpy.ops.object.select_all(action='DESELECT') 360 361 # アーマチュア作成 362 if self.is_armature: 363 arm = bpy.data.armatures.new(model_name1 + ".armature") 364 arm_ob = bpy.data.objects.new (model_name1 + ".armature", arm) 365 compat.link(bpy.context.scene, arm_ob) 366 compat.set_select(arm_ob, True) 367 compat.set_active(context, arm_ob) 368 369 arm.show_names = prefs.show_bone_names 370 arm.show_axes = prefs.show_bone_axes 371 arm.show_bone_custom_shapes = prefs.show_bone_custom_shapes 372 arm.show_group_colors = prefs.show_bone_group_colors 373 if compat.IS_LEGACY: 374 arm_ob.show_x_ray = prefs.show_bone_in_front 375 else: 376 arm_ob.show_in_front = prefs.show_bone_in_front 377 378 bpy.ops.object.mode_set(mode='EDIT') 379 380 is_odd_scale_bone = False 381 382 # 基幹ボーンのみ作成 383 child_data = [] 384 for data in bone_data: 385 if not data['parent_name']: 386 bone = arm.edit_bones.new(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 387 bone.head, bone.tail = (0, 0, 0), (0, 1, 0) 388 bone.use_deform = False 389 390 #co.x, co.y, co.z = -co.x, co.z, -co.y 391 #rot = compat.mul(rot, mathutils.Quaternion((0, 0, 1), math.radians(90))) 392 #rot.w, rot.x, rot.y, rot.z = -rot.w, -rot.x, rot.z, -rot.y 393 394 #co = data['co' ].copy() 395 #rot = data['rot'].copy() 396 #co.x, co.y, co.z = -co.x, -co.z, co.y 397 #rot.w, rot.x, rot.y, rot.z = -rot.w, -rot.x, -rot.z, rot.y 398 ##rot = compat.mul(rot, mathutils.Quaternion((0, 0, 1), math.radians(-90))) 399 #rot = compat.convert_cm_to_bl_bone_rotation(rot) 400 #mat = compat.mul(mathutils.Matrix.Translation(co), rot.to_matrix().to_4x4()) 401 402 co_mat = mathutils.Matrix.Translation(data['co'].copy() * self.scale) 403 rot = mathutils.Quaternion(data['rot'].copy()) 404 #rot = compat.convert_cm_to_bl_bone_rotation(rot) 405 rot_mat = rot.to_matrix().to_4x4() 406 #rot_mat = compat.convert_cm_to_bl_bone_rotation(rot_mat) 407 mat = compat.mul(co_mat, rot_mat) 408 mat = compat.convert_cm_to_bl_bone_rotation(mat) 409 mat = compat.convert_cm_to_bl_space(mat) 410 #mat = compat.mul(mat, compat.CM_TO_BL_LOCAL_BONE_MAT4) 411 412 413 #fix_mat_scale = mathutils.Matrix.Scale(-1, 4, (1, 0, 0)) 414 #fix_mat_before = mathutils.Euler((math.radians(90), 0, 0), 'XYZ').to_matrix().to_4x4() 415 #fix_mat_after = mathutils.Euler((0, 0, math.radians(90)), 'XYZ').to_matrix().to_4x4() 416 417 #compat.set_bone_matrix(bone, compat.mul4(fix_mat_scale, fix_mat_before, mat, fix_mat_after)) 418 compat.set_bone_matrix(bone, mat) 419 420 421 bone["cm3d2_scl_bone"] = 1 if data['scl'] else 0 422 if 'scale' in data: 423 bone['cm3d2_bone_scale'] = data['scale'] 424 scale = mathutils.Vector(data['scale']) 425 if ( scale - mathutils.Vector((1,1,1)) ).length > 1e-5: 426 is_odd_scale_bone = True 427 self.report(type={'WARNING'}, message=f_tip_("Bone '{bone_name}' has odd scale '{bone_scale}' (odd by {bone_diff})", bone_name=bone.name, bone_scale=scale, bone_diff=( scale - mathutils.Vector((1,1,1)) ).length)) 428 scale *= self.scale * 0.01 429 scale = compat.convert_cm_to_bl_bone_rotation(scale) 430 bone.bbone_x = scale.x 431 bone.bbone_z = scale.z 432 #look = bone.tail - bone.head 433 #look *= scale.y 434 #bone.tail = look + bone.head 435 else: 436 child_data.append(data) 437 context.window_manager.progress_update(1.333) 438 439 # 子ボーンを追加していく 440 while len(child_data): 441 data = child_data.pop(0) 442 parent = arm.edit_bones.get(common.decode_bone_name(data['parent_name'], self.is_convert_bone_weight_names)) 443 if parent: 444 bone = arm.edit_bones.new(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 445 bone.parent = parent 446 bone.head, bone.tail = (0, 0, 0), (0, 1, 0) 447 bone.use_deform = False 448 449 #parent_mats = [] 450 #current_bone = bone 451 #while current_bone: 452 # for b in bone_data: 453 # if common.decode_bone_name(b['name'], self.is_convert_bone_weight_names) == current_bone.name: 454 # local_co = b['co' ].copy() 455 # local_rot = b['rot'].copy() 456 # break 457 # 458 # local_co_mat = mathutils.Matrix.Translation(local_co) 459 # local_rot_mat = local_rot.to_matrix().to_4x4() 460 # parent_mats.append(compat.mul(local_co_mat, local_rot_mat)) 461 # 462 # current_bone = current_bone.parent 463 #parent_mats.reverse() 464 # 465 #mat = mathutils.Matrix() 466 #for local_mat in parent_mats: 467 # mat = compat.mul(mat, local_mat) 468 #mat *= self.scale 469 #mat = compat.convert_cm_to_bl_space(mat) 470 #mat = compat.convert_cm_to_bl_bone_rotation(mat) 471 472 #parent_mat = compat.mul( 473 # mathutils.Matrix.Translation(parent.matrix.to_translation()), 474 # parent.matrix.to_quaternion().to_matrix().to_4x4() 475 #) 476 477 parent_mat = parent.matrix 478 479 local_co = data['co' ].copy() * self.scale 480 local_rot = data['rot'].copy() 481 #local_rot = compat.convert_cm_to_bl_bone_rotation(rot) 482 local_co_mat = mathutils.Matrix.Translation(local_co) 483 local_rot_mat = local_rot.to_matrix().to_4x4() 484 local_mat = compat.mul(local_co_mat, local_rot_mat) 485 local_mat = compat.convert_cm_to_bl_bone_space(local_mat) 486 #local_mat = compat.mul(local_mat, mathutils.Matrix.Diagonal((1,1,1)).to_4x4()) 487 mat = compat.mul(parent_mat, local_mat) 488 mat = compat.convert_cm_to_bl_bone_rotation(mat) 489 490 491 #co_mat = compat.mul( parent.matrix.inverted(), compat.convert_cm_to_bl_local_bone_mat4(local_co_mat) ) 492 #rot_mat = compat.mul( local_rot_mat, compat.CM_TO_BL_LOCAL_BONE_MAT4 ) 493 #mat = compat.ul(co_mat, rot_mat) 494 #local_mat = compat.mul(local_co_mat, local_rot_mat) 495 #local_mat *= self.scale 496 #mat = compat.mul( parent.matrix, compat.convert_cm_to_bl_local_bone(local_mat) ) 497 #mat *= self.scale 498 499 #mat *= self.scale 500 501 #co.x, co.y, co.z = -co.y, co.z, co.x 502 #rot.w, rot.x, rot.y, rot.z = rot.w, rot.y, -rot.z, -rot.x 503 504 #co = data['co' ].copy() * self.scale 505 #rot = data['rot'].copy() 506 #co.x, co.y, co.z = co.z, -co.x, co.y 507 ##co = compat.convert_cm_to_bl_local_bone(co) 508 ##rot.w, rot.x, rot.y, rot.z = rot.w, -rot.z, rot.x, -rot.y 509 ##rot.w, rot.x, rot.y, rot.z = rot.w, -rot.z, rot.x, -rot.y 510 #local_mat = compat.mul(mathutils.Matrix.Translation(co), rot.to_matrix().to_4x4()) 511 #mat = compat.mul( parent.matrix, local_mat ) 512 ##mat *= self.scale 513 514 #fix_mat_scale = mathutils.Matrix.Scale(-1, 4, (1, 0, 0)) 515 #fix_mat_before = mathutils.Euler((math.radians(90), 0, 0), 'XYZ').to_matrix().to_4x4() 516 #fix_mat_after = mathutils.Euler((0, 0, math.radians(90)), 'XYZ').to_matrix().to_4x4() 517 518 #compat.set_bone_matrix(bone, compat.mul4(fix_mat_scale, fix_mat_before, mat, fix_mat_after)) 519 compat.set_bone_matrix(bone, mat) 520 521 bone['cm3d2_scl_bone'] = 1 if data['scl'] else 0 522 if 'scale' in data: 523 bone['cm3d2_bone_scale'] = data['scale'] 524 scale = mathutils.Vector(data['scale']) 525 if ( scale - mathutils.Vector((1,1,1)) ).length > 1e-5: 526 is_odd_scale_bone = True 527 self.report(type={'WARNING'}, message=f_tip_("Bone '{bone_name}' has odd scale '{bone_scale}' (odd by {bone_diff})", bone_name=bone.name, bone_scale=scale, bone_diff=( scale - mathutils.Vector((1,1,1)) ).length)) 528 scale *= self.scale * 0.01 529 bone.bbone_x = scale.x 530 bone.bbone_z = scale.z 531 #bone.bbone_segments = scale.y 532 #look = bone.tail - bone.head 533 #look *= scale.y 534 #bone.tail = look + bone.head 535 else: 536 child_data.append(data) 537 context.window_manager.progress_update(1.666) 538 539 # Configure bones in local bone data 540 is_local_bones_corrupt = False 541 base_bone = arm.edit_bones.get(common.decode_bone_name(model_name2, self.is_convert_bone_weight_names)) 542 base_bone_offset = base_bone.matrix.copy() 543 base_bone_offset = compat.mul(mathutils.Matrix.Scale(-1, 4, (1, 0, 0)), base_bone_offset) 544 base_bone_offset = compat.convert_bl_to_cm_bone_rotation(base_bone_offset) 545 print(base_bone_offset) 546 print(f"base_bone_offset @ I =\n{base_bone_offset @ mathutils.Matrix.Identity(4)}") 547 #base_bone_offset = mathutils.Matrix.Identity(4) # compat.mul(base_bone_mat.inverted(), base_bone_mat) 548 549 def setup_local_bone(bone, mat, isRoot=False): 550 pos = compat.transform_inverse(mat.transposed()).translation 551 mat.row[3] = (0.0, 0.0, 0.0, 1.0) 552 mat.translation = pos 553 mat.translation *= self.scale 554 offset_mat = mat.copy() 555 if not common.is_descendant_of(bone, base_bone): 556 mat = compat.mul(base_bone_offset, mat) 557 #mat.translation = mat.translation + base_bone_offset.translation 558 mat = compat.convert_cm_to_bl_bone_rotation(mat) 559 mat = compat.mul(mathutils.Matrix.Scale(-1, 4, (1, 0, 0)), mat) 560 561 562 # The matrices from the local bone data are more precise rotations, but make sure they aren't corrupted 563 old_pos, old_rot, old_scale = bone.matrix.decompose() 564 compat.set_bone_matrix(bone, mat) 565 new_pos, new_rot, new_scale = bone.matrix.decompose() 566 dif_pos = (new_pos-old_pos).length/self.scale 567 dif_rot = old_rot.rotation_difference(new_rot) 568 if dif_pos > 0.1 or dif_rot.w < .9: 569 print(dif_pos, dif_rot) 570 is_local_bones_corrupt = True 571 #self.report(type={'WARNING'}, message="Found potentially corrupt local bone data, please re-import with \"Use Local Bone Data\" disabled.") 572 return mat 573 574 for data in local_bone_data: 575 if self.is_use_local_bones and data['name'] == model_name2: 576 bone = arm.edit_bones.get(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 577 mat = mathutils.Matrix(data['matrix']) 578 print("Found base bone in local bone data!") 579 #base_bone_offset = compat.mul(compat.transform_inverse(base_bone_offset), setup_local_bone(bone, mat, isRoot=True)) 580 581 582 for data in local_bone_data: 583 bone = arm.edit_bones.get(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 584 bone.use_deform = True 585 if self.is_use_local_bones and not data['name'] == model_name2: 586 mat = mathutils.Matrix(data['matrix']) 587 setup_local_bone(bone, mat) 588 589 590 def distOnRay(pos0, pos1, point): 591 w = point - pos0 592 d = (pos1 - pos0).normalized() 593 return w.dot(d) / d.dot(d) 594 595 # ボーン整頓 596 for bone in arm.edit_bones: 597 if len(bone.children) == 0: 598 if bone.parent: 599 bone.length = bone.parent.length * 0.5 600 else: 601 bone.length = 0.2 * self.scale 602 elif len(bone.children) == 1: 603 co = bone.children[0].head - bone.head 604 bone.length = co.length 605 elif len(bone.children) >= 2: 606 if bone.parent: 607 max_len = 0.0 608 for child_bone in bone.children: 609 if "Pelvis" in bone.name: 610 dist = (child_bone.head - bone.head).length 611 else: 612 dist = distOnRay(bone.head, bone.tail, child_bone.head) 613 if dist > max_len: 614 max_len = dist 615 bone.length = max_len 616 else: 617 bone.length = 0.2 * self.scale 618 for bone in arm.edit_bones: 619 if len(bone.children) == 0: 620 if bone.parent: 621 bone.length = bone.parent.length * 0.5 622 623 # Make sure no bones are length 0, otherwise blender deletes them 624 for bone in arm.edit_bones: 625 min_length = 0.0001 626 if bone.length < min_length: 627 bone.length = min_length 628 629 # 一部ボーン削除 630 if self.is_armature_clean: 631 for bone in arm.edit_bones: 632 for b in local_bone_data: 633 name = common.decode_bone_name(b['name'], self.is_convert_bone_weight_names) 634 if bone.name == name: 635 break 636 else: 637 arm.edit_bones.remove(bone) 638 639 arm.layers[16] = True 640 compat.set_display_type(arm, prefs.bone_display_type) 641 bpy.ops.armature.select_all(action='DESELECT') 642 bpy.ops.object.mode_set(mode='OBJECT') 643 if self.is_custom_bones: 644 print("Set custom bones") 645 for pose_bone in arm_ob.pose.bones: 646 pose_bone.custom_shape = custom_bone_ob 647 context.window_manager.progress_update(2) 648 649 if self.is_mesh: 650 ob, me = self.create_mesh(context, model_name1, vertex_data, face_data) 651 # オブジェクト変形 652 CNV_OT_align_to_cm3d2_base_bone.from_bone_data(ob, bone_data, local_bone_data, base_bone_name=model_name2, scale=self.scale) 653 context.window_manager.progress_update(3) 654 655 self.create_uvs(context, me, vertex_data, extra_uv_uses) 656 context.window_manager.progress_update(4) 657 658 self.create_vertex_groups(context, ob, vertex_data, local_bone_data) 659 context.window_manager.progress_update(5) 660 661 self.create_shapekeys(context, ob, misc_data) 662 context.window_manager.progress_update(6) 663 664 # マテリアル追加 665 progress_count_total = 0.0 666 for data in material_data: 667 progress_count_total += 1 #len(data['data']) 668 self.progress_plus_value = 1.0 / (progress_count_total if progress_count_total > 0.0 else 1.0) 669 self.progress_count = 6.0 670 671 face_seek = 0 672 mates_set = set() 673 override = context.copy() 674 override['object'] = ob 675 prefs = common.preferences() 676 for index, data in enumerate(material_data): 677 print(f_("material count: {num} of {count}", num=index, count=material_count)) 678 if prefs.mate_unread_same_value and data.name in mates_set: 679 continue 680 mates_set.add(data.name) 681 #common.preferences().mate_unread_same_value 682 bpy.ops.object.material_slot_add(override) 683 mate = context.blend_data.materials.new(data.name)#['name1']) 684 #mate['shader1'] = data['name2'] 685 #mate['shader2'] = data['name3'] 686 687 ob.material_slots[-1].material = mate 688 # 面にマテリアル割り当て 689 for i in range(face_seek, face_seek + len(face_data[index])): 690 me.polygons[i].material_index = index 691 face_seek += len(face_data[index]) 692 693 # テクスチャ追加 694 if compat.IS_LEGACY: 695 #self.create_mateprop_old(context, me, texes_set, mate, index, data) 696 cm3d2_data.MaterialHandler.apply_to_old(override, mate, data) 697 common.decorate_material(mate, self.is_decorate, me, index) 698 else: 699 #self.create_mateprop(context, me, texes_set, mate, index, data) 700 cm3d2_data.MaterialHandler.apply_to(override, mate, data) 701 common.decorate_material(mate, self.is_decorate, me, index) 702 common.setup_material(mate) 703 704 ob.active_material_index = 0 705 context.window_manager.progress_update(7) 706 707 # メッシュ整頓 708 pre_mesh_select_mode = context.tool_settings.mesh_select_mode[:] 709 710 # Too buggy on versions before 2.91 so just disable it outright 711 #if self.is_sharp and (compat.IS_LEGACY or bpy.app.version < (2, 91)): 712 # context.tool_settings.mesh_select_mode = (False, True, False) 713 # bpy.ops.object.mode_set(mode='EDIT') 714 # 715 # bpy.ops.mesh.select_non_manifold(extend=False, use_wire=True, use_boundary=True, use_multi_face=False, use_non_contiguous=False, use_verts=False) 716 # for is_comparison, vert in zip(comparison_data, me.vertices): 717 # if is_comparison: 718 # vert.select = False 719 # bpy.ops.mesh.mark_sharp(use_verts=False) 720 # 721 # bpy.ops.object.mode_set(mode='OBJECT') 722 723 can_mark_sharp = not compat.IS_LEGACY and bpy.app.version >= (2, 91) 724 725 if self.is_remove_doubles: 726 context.tool_settings.mesh_select_mode = (True, False, False) 727 bpy.ops.object.mode_set(mode='EDIT') 728 if not self.is_sharp or not can_mark_sharp: 729 bpy.ops.mesh.select_all(action='DESELECT') 730 bpy.ops.object.mode_set(mode='OBJECT') 731 for is_comparison, vert in zip(comparison_data, me.vertices): 732 if is_comparison: 733 vert.select = True 734 bpy.ops.object.mode_set(mode='EDIT') 735 else: 736 bpy.ops.mesh.select_all(action='SELECT') 737 738 if not can_mark_sharp: 739 bpy.ops.mesh.remove_doubles(threshold=0.000001/5 * self.scale) 740 else: 741 bpy.ops.mesh.remove_doubles(threshold=0.000001/5 * self.scale, use_sharp_edge_from_normals=self.is_sharp) 742 bpy.ops.object.mode_set(mode='OBJECT') 743 744 context.tool_settings.mesh_select_mode = pre_mesh_select_mode 745 746 if self.is_seam: 747 bpy.ops.object.mode_set(mode='EDIT') 748 bpy.ops.mesh.select_all(action='SELECT') 749 bpy.ops.uv.select_all(action='SELECT') 750 bpy.ops.uv.seams_from_islands() 751 bpy.ops.object.mode_set(mode='OBJECT') 752 bpy.ops.object.mode_set(mode='EDIT') 753 bpy.ops.mesh.select_all(action='DESELECT') 754 bpy.ops.object.mode_set(mode='OBJECT') 755 756 if self.is_armature: 757 mod = ob.modifiers.new("Armature", 'ARMATURE') 758 mod.object = arm_ob 759 compat.set_active(context, arm_ob) 760 bpy.ops.object.parent_set(type='OBJECT', keep_transform=True) 761 compat.set_active(context, ob) 762 context.window_manager.progress_update(8) 763 764 # マテリアル情報のテキスト埋め込み 765 if self.is_mate_data_text: 766 for index, data in enumerate(material_data): 767 txt_name = "Material:" + str(index) 768 if txt_name in context.blend_data.texts: 769 txt = context.blend_data.texts[txt_name] 770 txt.clear() 771 else: 772 txt = context.blend_data.texts.new(txt_name) 773 txt.write(data.to_text()) 774 775 # txt.write("1000" + "\n") 776 # txt.write(data['name1'].lower() + "\n") 777 # txt.write(data['name1'] + "\n") 778 # txt.write(data['name2'] + "\n") 779 # txt.write(data['name3'] + "\n") 780 # txt.write("\n") 781 # for tex_data in data['data']: 782 # txt.write(tex_data['type'] + "\n") 783 # if tex_data['type'] == 'tex': 784 # txt.write("\t" + tex_data['name'] + "\n") 785 # txt.write("\t" + tex_data['type2'] + "\n") 786 # if tex_data['type2'] == 'tex2d': 787 # txt.write("\t" + tex_data['name2'] + "\n") 788 # txt.write("\t" + tex_data['path'] + "\n") 789 # map_list = tex_data['tex_map'] 790 # tex_map = " ".join([str(map_list[0]), str(map_list[1]), str(map_list[2]), str(map_list[3])]) 791 # txt.write("\t" + tex_map + "\n") 792 # elif tex_data['type'] == 'col': 793 # txt.write("\t" + tex_data['name'] + "\n") 794 # col = " ".join([str(tex_data['color'][0]), str(tex_data['color'][1]), str(tex_data['color'][2]), str(tex_data['color'][3])]) 795 # txt.write("\t" + col + "\n") 796 # elif tex_data['type'] == 'f': 797 # txt.write("\t" + tex_data['name'] + "\n") 798 # txt.write("\t" + str(tex_data['float']) + "\n") 799 # txt.current_line_index = 0 800 context.window_manager.progress_update(9) 801 802 # ボーン情報のテキスト埋め込み 803 if self.is_bone_data_text: 804 if "BoneData" in context.blend_data.texts: 805 txt = context.blend_data.texts["BoneData"] 806 txt.clear() 807 else: 808 txt = context.blend_data.texts.new("BoneData") 809 for i, data in enumerate(bone_data): 810 s = ",".join([data['name'], str(data['scl']), ""]) 811 parent_index = data['parent_index'] 812 if -1 < parent_index: 813 s += bone_data[parent_index]['name'] + "," 814 else: 815 s += "None" + "," 816 s += " ".join([str(data['co'][0]), str(data['co'][1]), str(data['co'][2])]) + "," 817 s += " ".join([str(data['rot'][0]), str(data['rot'][1]), str(data['rot'][2]), str(data['rot'][3])]) 818 if model_ver >= 2001: 819 if 'scale' in data: 820 s += ",1," + " ".join(map(str, data['scale'])) 821 else: 822 s += ",0" 823 824 if self.is_bone_data_text: 825 txt.write(s + "\n") 826 if self.is_mesh and self.is_bone_data_obj_property: 827 ob["BoneData:" + str(i)] = s 828 if self.is_armature and self.is_bone_data_arm_property: 829 arm["BoneData:" + str(i)] = s 830 if self.is_bone_data_text: 831 txt['BaseBone'] = model_name2 832 txt.current_line_index = 0 833 context.window_manager.progress_update(10) 834 835 # ローカルボーン情報のテキスト埋め込み 836 if self.is_bone_data_text: 837 if "LocalBoneData" in context.blend_data.texts: 838 txt = context.blend_data.texts["LocalBoneData"] 839 txt.clear() 840 else: 841 txt = context.blend_data.texts.new("LocalBoneData") 842 for i, data in enumerate(local_bone_data): 843 s = data['name'] + "," 844 845 mat_list = list(data['matrix'][0]) 846 mat_list.extend(list(data['matrix'][1])) 847 mat_list.extend(list(data['matrix'][2])) 848 mat_list.extend(list(data['matrix'][3])) 849 for j, f in enumerate(mat_list): 850 mat_list[j] = str(f) 851 s += " ".join(mat_list) 852 853 if self.is_bone_data_text: 854 txt.write(s + "\n") 855 if self.is_mesh and self.is_bone_data_obj_property: 856 ob["LocalBoneData:" + str(i)] = s 857 if self.is_armature and self.is_bone_data_arm_property: 858 arm["LocalBoneData:" + str(i)] = s 859 if self.is_bone_data_text: 860 txt['BaseBone'] = model_name2 861 txt.current_line_index = 0 862 863 if self.is_mesh and self.is_bone_data_obj_property: 864 ob['BaseBone'] = model_name2 865 if model_ver >= 1000: 866 ob['ModelVersion'] = model_ver 867 if self.is_armature and self.is_bone_data_arm_property: 868 arm['BaseBone'] = model_name2 869 if model_ver >= 1000: 870 arm['ModelVersion'] = model_ver 871 context.window_manager.progress_end() 872 873 require_time = time.time() - start_time 874 filesize = os.path.getsize(self.filepath) 875 filesize_str = "バイト" 876 if 1024 * 1024 < filesize: 877 filesize = filesize / (1024 * 1024.0) 878 filesize_str = "MB" 879 elif 1024 < filesize: 880 filesize = filesize / 1024.0 881 filesize_str = "KB" 882 self.report(type={'INFO'}, message=f_tip_("modelのインポートが完了しました ({} {}/ {:.2f} 秒)", filesize, filesize_str, require_time)) 883 884 if is_odd_scale_bone: 885 self.report(type={'WARNING'}, message="Found bone with a scale not equal to 1.") 886 if is_local_bones_corrupt: 887 self.report(type={'ERROR'}, message="Found potentially corrupt local bone data, please re-import with \"Use Local Bone Data\" disabled.") 888 return {'FINISHED'} 889 890 def create_mesh(self, context, model_name1, vertex_data, face_data) -> (bpy.types.Object, bpy.types.Mesh): 891 # メッシュ作成 892 me = context.blend_data.meshes.new(model_name1) 893 verts, faces = [], [] 894 for data in vertex_data: 895 #co = list(data['co'][:]) 896 #co[0] = -co[0] 897 #co[0] *= self.scale 898 #co[1] *= self.scale 899 #co[2] *= self.scale 900 co = compat.convert_cm_to_bl_space( mathutils.Vector(data['co']) * self.scale ) 901 #co = mathutils.Vector(data['co']) * self.scale 902 verts.append(co) 903 context.window_manager.progress_update(2.25) 904 for data in face_data: 905 faces.extend(data) 906 context.window_manager.progress_update(2.5) 907 me.from_pydata(verts, [], faces) 908 909 # オブジェクト化 910 ob = context.blend_data.objects.new(model_name1, me) 911 ob.rotation_mode = 'QUATERNION' 912 compat.link(context.scene, ob) 913 compat.set_select(ob, True) 914 compat.set_active(context, ob) 915 bpy.ops.object.shade_smooth() 916 context.window_manager.progress_update(2.75) 917 918 # Custom Split Normals 919 #normals_color = me.vertex_colors.new(name=f"Basis_normals", do_init=False) or me.vertex_colors[-1] 920 #for vert_index, vert in enumerate(vertex_data): 921 # no = compat.convert_cm_to_bl_space( mathutils.Vector(vert['normal']) ) #mathutils.Vector(vert['normal']) * mathutils.Vector((-1,1,1)) # 922 # no.normalize() 923 # print(no) 924 # for loop_index in vert_loops[vert_index]: 925 # #normals[loop_index] = no 926 # normals_color.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1) 927 # *no, #*(no * 0.5 + mathutils.Vector([0.5]*3)), 928 # 1, 929 # ) 930 #me.normals_split_custom_set(normals) 931 me.normals_split_custom_set_from_vertices( 932 tuple( 933 compat.convert_cm_to_bl_space( mathutils.Vector(vert['normal']) ) 934 for vert in vertex_data 935 ) 936 ) 937 me.use_auto_smooth = True 938 939 return ob, me 940 941 def create_vertex_groups(self, context, ob, vertex_data, local_bone_data): 942 # 頂点グループ作成 943 for data in local_bone_data: 944 ob.vertex_groups.new(name=common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 945 context.window_manager.progress_update(4.333) 946 947 for vert_index, data in enumerate(vertex_data): 948 for weight in data['weights']: 949 if 0.0 < weight['value']: 950 vertex_group = ob.vertex_groups[common.decode_bone_name(weight['name'], self.is_convert_bone_weight_names)] 951 vertex_group.add([vert_index], weight['value'], 'REPLACE') 952 context.window_manager.progress_update(4.666) 953 954 if self.is_vertex_group_sort: 955 bpy.ops.object.vertex_group_sort(sort_type='NAME') 956 957 if self.is_remove_empty_vertex_group: 958 for vg in ob.vertex_groups[:]: 959 for vert in ob.data.vertices: 960 for group in vert.groups: 961 if group.group == vg.index: 962 if 0.0 < group.weight: 963 break 964 else: # if for-loop didn't break 965 continue 966 break 967 else: # if for-loop didn't break 968 ob.vertex_groups.remove(vg) 969 970 ob.vertex_groups.active_index = 0 971 972 def create_uvs(self, context, me, vertex_data, extra_uv_uses): 973 # UV作成 974 bm = bmesh.new() 975 bm.from_mesh(me) 976 bm.loops.layers.uv.new(f_data_("MainUV")) 977 for i, used in enumerate(extra_uv_uses): 978 if used: 979 bm.loops.layers.uv.new(f_data_("ExtraUV{num}", num=i)) 980 for face in bm.faces: 981 for loop in face.loops: 982 loop[bm.loops.layers.uv[0]].uv = vertex_data[loop.vert.index]['uv'] 983 for extra_uv_index, extra_uv in enumerate(vertex_data[loop.vert.index]['extra_uvs']): 984 loop[bm.loops.layers.uv[extra_uv_index+1]].uv = extra_uv 985 bm.to_mesh(me) 986 bm.free() 987 988 def create_shapekeys(self, context, ob, misc_data): 989 # モーフ追加 990 me = ob.data 991 992 is_use_attributes = (not compat.IS_LEGACY and bpy.app.version >= (2,92)) 993 is_fast_create = (not compat.IS_LEGACY and bpy.app.version >= (3,2)) 994 995 #if not is_fast_create: 996 # bpy.ops.object.mode_set(mode='VERTEX_PAINT') 997 # prev_brush_color = context.tool_settings.vertex_paint.brush.color 998 999 vert_loops = dict() 1000 for loop_index, loop in enumerate(me.loops): 1001 vert_loops.setdefault(loop.vertex_index, list()).append(loop_index) 1002 1003 def fill_color_layer(layer, color): 1004 import numpy as np 1005 color_np = np.array(color, dtype=float) 1006 color_values = np.broadcast_to(color_np, (len(me.loops), len(color_np))) 1007 layer.data.foreach_set('color', color_values.ravel()) 1008 1009 def create_normals_color(name): 1010 default_color = (0.5, 0.5, 0.5, 1.0) 1011 1012 #if is_fast_create: 1013 # bpy.ops.geometry.color_attribute_add(name=name, domain='CORNER', data_type='FLOAT_COLOR', color=default_color) 1014 # return me.attributes.active 1015 1016 if is_use_attributes: 1017 normals_color = me.attributes.new(name, 'FLOAT_COLOR', 'CORNER') 1018 else: 1019 normals_color = me.vertex_colors.new(name=name, do_init=False) or me.vertex_colors[-1] 1020 1021 fill_color_layer(normals_color, default_color) 1022 1023 return normals_color 1024 1025 def create_unknown_color(data): 1026 unknown_color = None 1027 if len(data['data']) and data['data'][0]['color']: 1028 if is_use_attributes: 1029 unknown_color = me.attributes.new(f"{data['name']}_unknown", 'FLOAT_COLOR', 'CORNER') 1030 else: 1031 unknown_color = me.vertex_colors.new(name=f"{data['name']}_unknown", do_init=False) or me.vertex_colors[-1] 1032 return unknown_color 1033 1034 def set_shape_key_data(shape_key, normals_color, unknown_color): 1035 for vert in data['data']: 1036 vert_index = vert['index'] 1037 co = compat.convert_cm_to_bl_space( mathutils.Vector(vert['co']) * self.scale ) 1038 no = compat.convert_cm_to_bl_space( mathutils.Vector(vert['normal'])) 1039 shape_key.data[vert_index].co = shape_key.data[vert_index].co + co 1040 1041 write_vertex_colors(vert, no, normals_color, unknown_color) 1042 1043 def write_vertex_colors(vert, no, normals_color, unknown_color): 1044 for loop_index in vert_loops[vert['index']]: 1045 normals_color.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1) 1046 no[0] * 0.5 + 0.5, 1047 no[1] * 0.5 + 0.5, 1048 no[2] * 0.5 + 0.5, 1049 1, 1050 ) 1051 if not vert['color']: 1052 continue 1053 unknown_color.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1) 1054 vert['color'][0] * 0.5 * vert['color'][3] + 0.5, 1055 vert['color'][1] * 0.5 * vert['color'][3] + 0.5, 1056 vert['color'][2] * 0.5 * vert['color'][3] + 0.5, 1057 1, 1058 ) 1059 1060 morph_count = -1 1061 for data in misc_data: 1062 if not data['type'] == 'morph': 1063 continue 1064 1065 morph_count += 1 1066 1067 if morph_count == 0: 1068 bpy.ops.object.shape_key_add(from_mix=False) 1069 me.shape_keys.name = ob.name 1070 shape_key = ob.shape_key_add(name=data['name'], from_mix=False) 1071 1072 normals_color = create_normals_color(f"{data['name']}_delta_normals") 1073 unknown_color = create_unknown_color(data) 1074 set_shape_key_data(shape_key, normals_color, unknown_color) 1075 1076 1077 def create_mateprop_old(self, context, me, tex_set, mate, mate_idx, data: list): 1078 # create_matepropとの違いは、slot_indexの有無、nodeの接続・配置処理のみ 1079 1080 prefs = common.preferences() 1081 # テクスチャ追加 1082 slot_index = 0 1083 for tex_data in data['data']: 1084 if prefs.mate_unread_same_value: 1085 if tex_data['name'] in tex_set: 1086 continue 1087 tex_set.add(tex_data['name']) 1088 1089 node_name = tex_data['name'] 1090 if tex_data['type'] == 'tex': 1091 path = tex_data['path'] 1092 tex_map_data = tex_data['tex_map'] 1093 common.create_tex(context, mate, node_name, tex_data['name2'], path, path, tex_map_data, prefs.is_replace_cm3d2_tex, slot_index) 1094 1095 elif tex_data['type'] == 'col': 1096 col = tex_data['color'] 1097 common.create_col(context, mate, node_name, col, slot_index) 1098 1099 elif tex_data['type'] == 'f': 1100 f = tex_data['float'] 1101 common.create_f(context, mate, node_name, f, slot_index) 1102 1103 slot_index += 1 1104 1105 self.progress(context) 1106 1107 def create_mateprop(self, context, me, tex_set, mate, mate_idx, data: list): 1108 if mate.use_nodes is False: 1109 mate.use_nodes = True 1110 1111 nodes = mate.node_tree.nodes 1112 prefs = common.preferences() 1113 1114 for prop_data in data['data']: 1115 if prefs.mate_unread_same_value: 1116 if prop_data['name'] in tex_set: 1117 continue 1118 tex_set.add(prop_data['name']) 1119 1120 if prop_data['type'] == 'tex': # テクスチャ追加 1121 prop_name = prop_data['name'] 1122 if prop_data['type2'] == 'tex2d': 1123 tex_name = prop_data['name2'] 1124 cm3d2path = prop_data['path'] 1125 tex_map = prop_data['tex_map'] 1126 tex = common.create_tex(context, mate, prop_name, tex_name, cm3d2path, cm3d2path, tex_map) 1127 1128 if prop_data['type2'] == 'tex2d': 1129 mapping = prop_data['tex_map'] 1130 tex_map = tex.texture_mapping 1131 tex_map.translation[0] = mapping[0] 1132 tex_map.translation[1] = mapping[1] 1133 tex_map.scale[0] = mapping[2] 1134 tex_map.scale[1] = mapping[3] 1135 1136 # ファイルの実体を割り当て 1137 if prefs.is_replace_cm3d2_tex: 1138 img = tex.image 1139 # col = mate.node_tree.nodes.new(type='ShaderNodeAttribute') 1140 # tex.image = bpy.data.images.load("C:\\path\\to\\im.jpg") 1141 replaced = common.replace_cm3d2_tex(img, self.texpath_dict, reload_path=False) 1142 if compat.IS_LEGACY and replaced and prop_name == '_MainTex': 1143 for face in me.polygons: 1144 if face.material_index == mate_idx: 1145 me.uv_textures.active.data[face.index].image = img 1146 else: 1147 common.create_tex(context, mate, prop_name) 1148 1149 elif prop_data['type'] == 'col': 1150 col = nodes.new(type='ShaderNodeRGB') 1151 col.name = col.label = prop_data['name'] 1152 # val.type = 'RGB' 1153 col.outputs[0].default_value = prop_data['color'][:4] 1154 1155 # mate.node_tree.links.new(bsdf.inputs['xxx'], val.outputs['Color']) 1156 # mate.node_tree.nodes.active = col 1157 1158 # slot = mate.texture_slots.create(tex_index) 1159 # mate.use_textures[tex_index] = False 1160 # slot.diffuse_color_factor = tex_data['color'][3] 1161 # slot.use_rgb_to_intensity = True 1162 # tex = context.blend_data.textures.new(tex_data['name'], 'BLEND') 1163 # slot.texture = tex 1164 1165 elif prop_data['type'] == 'f': 1166 val = nodes.new(type='ShaderNodeValue') 1167 val.name = prop_data['name'] 1168 val.label = prop_data['name'] 1169 # val.type = 'VALUE' 1170 # mate.node_tree.links.new(bsdf.inputs['xxx'], val.outputs['Value']) 1171 1172 val.outputs[0].default_value = prop_data['float'] 1173 1174 self.progress(context) 1175 1176 cm3d2_data.align_nodes(mate) 1177 1178 def progress(self, context): 1179 self.progress_count += self.progress_plus_value 1180 context.window_manager.progress_update(self.progress_count)
filepath: <_PropertyDeferred, <built-in function StringProperty>, {'subtype': 'FILE_PATH', 'attr': 'filepath'}> =
<_PropertyDeferred, <built-in function StringProperty>, {'subtype': 'FILE_PATH', 'attr': 'filepath'}>
filter_glob: <_PropertyDeferred, <built-in function StringProperty>, {'default': '*.model', 'options': {'HIDDEN'}, 'attr': 'filter_glob'}> =
<_PropertyDeferred, <built-in function StringProperty>, {'default': '*.model', 'options': {'HIDDEN'}, 'attr': 'filter_glob'}>
scale: <_PropertyDeferred, <built-in function FloatProperty>, {'name': '倍率', 'default': 5, 'min': 0.1, 'max': 100, 'soft_min': 0.1, 'soft_max': 100, 'step': 100, 'precision': 1, 'description': 'インポート時のメッシュ等の拡大率です', 'attr': 'scale'}> =
<_PropertyDeferred, <built-in function FloatProperty>, {'name': '倍率', 'default': 5, 'min': 0.1, 'max': 100, 'soft_min': 0.1, 'soft_max': 100, 'step': 100, 'precision': 1, 'description': 'インポート時のメッシュ等の拡大率です', 'attr': 'scale'}>
is_mesh: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'メッシュ生成', 'default': True, 'description': 'ポリゴンを読み込みます、大抵の場合オンでOKです', 'attr': 'is_mesh'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': 'メッシュ生成', 'default': True, 'description': 'ポリゴンを読み込みます、大抵の場合オンでOKです', 'attr': 'is_mesh'}>
is_remove_doubles: <_PropertyDeferred, <built-in function BoolProperty>, {'name': '重複頂点を結合', 'default': True, 'description': 'UVの切れ目でポリゴンが分かれている仕様なので、インポート時にくっつけます', 'attr': 'is_remove_doubles'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': '重複頂点を結合', 'default': True, 'description': 'UVの切れ目でポリゴンが分かれている仕様なので、インポート時にくっつけます', 'attr': 'is_remove_doubles'}>
is_seam: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'シームをつける', 'default': True, 'description': 'UVの切れ目にシームをつけます', 'attr': 'is_seam'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': 'シームをつける', 'default': True, 'description': 'UVの切れ目にシームをつけます', 'attr': 'is_seam'}>
is_sharp: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Mark Sharp', 'default': True, 'description': 'This will mark removed doubles on your mesh as sharp (or all free edges if not removing doubles).', 'attr': 'is_sharp'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Mark Sharp', 'default': True, 'description': 'This will mark removed doubles on your mesh as sharp (or all free edges if not removing doubles).', 'attr': 'is_sharp'}>
is_convert_bone_weight_names: <_PropertyDeferred, <built-in function BoolProperty>, {'name': '頂点グループ名をBlender用に変換', 'default': False, 'description': '全ての頂点グループ名をBlenderの左右対称編集で使えるように変換してから読み込みます', 'attr': 'is_convert_bone_weight_names'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': '頂点グループ名をBlender用に変換', 'default': False, 'description': '全ての頂点グループ名をBlenderの左右対称編集で使えるように変換してから読み込みます', 'attr': 'is_convert_bone_weight_names'}>
is_vertex_group_sort: <_PropertyDeferred, <built-in function BoolProperty>, {'name': '頂点グループを名前順ソート', 'default': True, 'description': '頂点グループを名前順でソートします', 'attr': 'is_vertex_group_sort'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': '頂点グループを名前順ソート', 'default': True, 'description': '頂点グループを名前順でソートします', 'attr': 'is_vertex_group_sort'}>
is_remove_empty_vertex_group: <_PropertyDeferred, <built-in function BoolProperty>, {'name': '割り当てのない頂点グループを削除', 'default': True, 'description': '全ての頂点に割り当てのない頂点グループを削除します', 'attr': 'is_remove_empty_vertex_group'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': '割り当てのない頂点グループを削除', 'default': True, 'description': '全ての頂点に割り当てのない頂点グループを削除します', 'attr': 'is_remove_empty_vertex_group'}>
reload_tex_cache: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'テクスチャキャッシュを再構成', 'default': False, 'description': 'texファイルを探す際、キャッシュを再構成します', 'attr': 'reload_tex_cache'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': 'テクスチャキャッシュを再構成', 'default': False, 'description': 'texファイルを探す際、キャッシュを再構成します', 'attr': 'reload_tex_cache'}>
is_decorate: <_PropertyDeferred, <built-in function BoolProperty>, {'name': '種類に合わせてマテリアルを装飾', 'default': True, 'attr': 'is_decorate'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': '種類に合わせてマテリアルを装飾', 'default': True, 'attr': 'is_decorate'}>
is_mate_data_text: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'テキストにマテリアル情報埋め込み', 'default': True, 'description': 'シェーダー情報をテキストに埋め込みます', 'attr': 'is_mate_data_text'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': 'テキストにマテリアル情報埋め込み', 'default': True, 'description': 'シェーダー情報をテキストに埋め込みます', 'attr': 'is_mate_data_text'}>
is_armature: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'アーマチュア生成', 'default': True, 'description': 'ウェイトを編集する時に役立つアーマチュアを読み込みます', 'attr': 'is_armature'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': 'アーマチュア生成', 'default': True, 'description': 'ウェイトを編集する時に役立つアーマチュアを読み込みます', 'attr': 'is_armature'}>
is_armature_clean: <_PropertyDeferred, <built-in function BoolProperty>, {'name': '不要なボーンを削除', 'default': False, 'description': 'ウェイトが無いボーンを削除します', 'attr': 'is_armature_clean'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': '不要なボーンを削除', 'default': False, 'description': 'ウェイトが無いボーンを削除します', 'attr': 'is_armature_clean'}>
is_custom_bones: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Use Custom Bones', 'default': False, 'description': 'Use the currently selected object for custom bone shapes.', 'attr': 'is_custom_bones'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Use Custom Bones', 'default': False, 'description': 'Use the currently selected object for custom bone shapes.', 'attr': 'is_custom_bones'}>
is_use_local_bones: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Use Local Bones', 'default': True, 'description': 'Use the Local Bone Data for orientation (more accurate)', 'attr': 'is_use_local_bones'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': 'Use Local Bones', 'default': True, 'description': 'Use the Local Bone Data for orientation (more accurate)', 'attr': 'is_use_local_bones'}>
is_bone_data_text: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'テキスト', 'default': True, 'description': 'ボーン情報をテキストとして読み込みます', 'attr': 'is_bone_data_text'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': 'テキスト', 'default': True, 'description': 'ボーン情報をテキストとして読み込みます', 'attr': 'is_bone_data_text'}>
is_bone_data_obj_property: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'オブジェクトのカスタムプロパティ', 'default': True, 'description': 'メッシュオブジェクトのカスタムプロパティにボーン情報を埋め込みます', 'attr': 'is_bone_data_obj_property'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': 'オブジェクトのカスタムプロパティ', 'default': True, 'description': 'メッシュオブジェクトのカスタムプロパティにボーン情報を埋め込みます', 'attr': 'is_bone_data_obj_property'}>
is_bone_data_arm_property: <_PropertyDeferred, <built-in function BoolProperty>, {'name': 'アーマチュアのカスタムプロパティ', 'default': True, 'description': 'アーマチュアデータのカスタムプロパティにボーン情報を埋め込みます', 'attr': 'is_bone_data_arm_property'}> =
<_PropertyDeferred, <built-in function BoolProperty>, {'name': 'アーマチュアのカスタムプロパティ', 'default': True, 'description': 'アーマチュアデータのカスタムプロパティにボーン情報を埋め込みます', 'attr': 'is_bone_data_arm_property'}>
def
invoke(self, context, event):
61 def invoke(self, context, event): 62 prefs = common.preferences() 63 if prefs.model_default_path: 64 self.filepath = common.default_cm3d2_dir(prefs.model_default_path, None, "model") 65 else: 66 self.filepath = common.default_cm3d2_dir(prefs.model_import_path, None, "model") 67 self.scale = prefs.scale 68 self.is_convert_bone_weight_names = prefs.is_convert_bone_weight_names 69 if compat.IS_LEGACY or bpy.app.version < (2, 91): 70 self.is_sharp = False 71 context.window_manager.fileselect_add(self) 72 return {'RUNNING_MODAL'}
def
draw(self, context):
74 def draw(self, context): 75 prefs = common.preferences() 76 self.layout.prop(self, 'scale') 77 78 box = self.layout.box() 79 box.prop(self, 'is_mesh', icon='MESH_DATA') 80 81 sub_box = box.box() 82 sub_box.enabled = self.is_mesh 83 sub_box.label(text="メッシュ") 84 sub_box.prop(self, 'is_remove_doubles', icon='STICKY_UVS_VERT') 85 sub_box.prop(self, 'is_seam' , icon=compat.icon('UV_EDGESEL')) 86 if not compat.IS_LEGACY and bpy.app.version >= (2, 91): 87 sub_box.prop(self, 'is_sharp', icon=compat.icon('EDGESEL')) 88 89 sub_box = box.box() 90 sub_box.enabled = self.is_mesh 91 sub_box.label(text="頂点グループ") 92 sub_box.prop(self, 'is_vertex_group_sort', icon='SORTALPHA') 93 sub_box.prop(self, 'is_remove_empty_vertex_group', icon='DISCLOSURE_TRI_DOWN') 94 sub_box.prop(self, 'is_convert_bone_weight_names', icon='BLENDER') 95 96 sub_box = box.box() 97 sub_box.enabled = self.is_mesh 98 sub_box.label(text="マテリアル") 99 sub_box.prop(prefs, 'is_replace_cm3d2_tex', icon='BORDERMOVE') 100 sub_box.prop(self, 'reload_tex_cache', icon='FILE_REFRESH') 101 if compat.IS_LEGACY: 102 sub_box.prop(self, 'is_decorate', icon=compat.icon('SHADING_TEXTURE')) 103 sub_box.prop(self, 'is_mate_data_text', icon='TEXT') 104 105 box = self.layout.box() 106 box.prop(self, 'is_armature', icon='ARMATURE_DATA') 107 108 sub_box = box.box() 109 sub_box.label(text="アーマチュア") 110 sub_box.prop(self , 'is_use_local_bones' , icon=compat.icon('GROUP_BONE'), text="Use Local Bone Data") 111 sub_box.prop(self , 'is_armature_clean' , icon=compat.icon('X' )) 112 sub_box.prop(self , 'is_convert_bone_weight_names', icon=compat.icon('BLENDER' ), text="ボーン名をBlender用に変換") 113 sub_box.prop(prefs, 'show_bone_in_front' , icon=compat.icon('HIDE_OFF' ), text="Show Bones in Front") 114 row = sub_box.row() 115 row.prop (self , 'is_custom_bones' , icon=compat.icon('BONE_DATA' ), text="Use Selected as Bone Shape" ) 116 row.enabled = bool(context.object) 117 118 box = self.layout.box() 119 box.label(text="ボーン情報埋め込み場所") 120 box.prop(self, 'is_bone_data_text', icon='TEXT') 121 box.prop(self, 'is_bone_data_obj_property', icon='OBJECT_DATA') 122 box.prop(self, 'is_bone_data_arm_property', icon='ARMATURE_DATA')
def
execute(self, context):
124 def execute(self, context): 125 start_time = time.time() 126 127 prefs = common.preferences() 128 prefs.model_import_path = self.filepath 129 prefs.scale = self.scale 130 context.window_manager.progress_begin(0, 10) 131 context.window_manager.progress_update(0) 132 133 custom_bone_ob = context.active_object 134 if not custom_bone_ob: 135 self.is_custom_bones = False 136 137 #global_matrix = bpy_extras.io_utils.axis_conversion(from_forward=self.axis_forward, from_up=self.axis_up).to_4x4() 138 139 try: 140 reader = open(self.filepath, 'rb') 141 except: 142 self.report(type={'ERROR'}, message=f_tip_("ファイルを開くのに失敗しました、アクセス不可かファイルが存在しません。file={}", self.filepath)) 143 return {'CANCELLED'} 144 145 self.texpath_dict = common.get_texpath_dict(reload=self.reload_tex_cache) 146 147 with reader: 148 # ヘッダー 149 ext = None 150 try: # luvoid : utf-8 decoding could possibly throw an error here 151 ext = common.read_str(reader) 152 except: 153 ext = False 154 if ext != 'CM3D2_MESH': 155 self.report(type={'ERROR'}, message="これはカスタムメイド3D2のモデルファイルではありません") 156 return {'CANCELLED'} 157 model_ver = struct.unpack('<i', reader.read(4))[0] 158 self.report(type={'INFO'}, message=f_tip_("Model Version = {version}", version=model_ver)) 159 context.window_manager.progress_update(0.1) 160 161 try: 162 # 名前群を取得 163 model_name1 = common.read_str(reader) 164 model_name2 = common.read_str(reader) 165 context.window_manager.progress_update(0.2) 166 167 # ボーン情報読み込み 168 bone_data = [] 169 bone_count = struct.unpack('<i', reader.read(4))[0] 170 for i in range(bone_count): 171 name = common.read_str(reader) 172 scl = struct.unpack('<B', reader.read(1))[0] 173 bone_data.append({'name': name, 'scl': scl}) 174 175 for i in range(bone_count): 176 parent_index = struct.unpack('<i', reader.read(4))[0] 177 parent_name = None 178 if parent_index != -1: 179 parent_name = bone_data[parent_index]['name'] 180 bone_data[i]['parent_index'] = parent_index 181 bone_data[i]['parent_name'] = parent_name 182 183 for i in range(bone_count): 184 x, y, z = struct.unpack('<3f', reader.read(3*4)) 185 bone_data[i]['co'] = mathutils.Vector((x, y, z)) 186 187 x, y, z = struct.unpack('<3f', reader.read(3*4)) 188 w = struct.unpack('<f', reader.read(4))[0] 189 bone_data[i]['rot'] = mathutils.Quaternion((w, x, y, z)) 190 if model_ver >= 2001: 191 use_scale = struct.unpack('<B', reader.read(1))[0] 192 if use_scale: 193 print(bone_data[i]['name'],"has scale data!") 194 scale_x, scale_y, scale_z = struct.unpack('<3f', reader.read(3*4)) 195 bone_data[i]['scale'] = [scale_x, scale_y, scale_z] 196 197 context.window_manager.progress_update(0.3) 198 199 print(f_("Reading vertex, mesh, and local bone count at 0x{num:02X}", num=reader.tell())) 200 vertex_count, mesh_count, local_bone_count = struct.unpack('<3i', reader.read(3*4)) 201 202 # ローカルボーン情報読み込み 203 local_bone_data = [] 204 for i in range(local_bone_count): 205 local_bone_data.append({'name': common.read_str(reader)}) 206 207 for i in range(local_bone_count): 208 row0 = struct.unpack('<4f', reader.read(4 * 4)) 209 row1 = struct.unpack('<4f', reader.read(4 * 4)) 210 row2 = struct.unpack('<4f', reader.read(4 * 4)) 211 row3 = struct.unpack('<4f', reader.read(4 * 4)) 212 local_bone_data[i]['matrix'] = mathutils.Matrix([row0, row1, row2, row3]) 213 context.window_manager.progress_update(0.4) 214 215 # 頂点情報読み込み 216 vertex_data = [] 217 print(f_("Reading vertex data at 0x{num:02X}", num=reader.tell())) 218 extra_uv_uses = [False] * 7 219 if model_ver >= 2102: # CR Edit Mode 220 extra_uv_uses = struct.unpack('<7?', reader.read(7)) 221 print(f_("extra_uv_uses = {boollist}", boollist=extra_uv_uses)) 222 for i in range(vertex_count): 223 co = struct.unpack('<3f', reader.read(3 * 4)) 224 no = struct.unpack('<3f', reader.read(3 * 4)) 225 uv = struct.unpack('<2f', reader.read(2 * 4)) 226 extra_uvs = [] # CR Edit 227 for i, used in enumerate(extra_uv_uses): 228 if used: 229 extra_uvs.append(struct.unpack('<2f', reader.read(2 * 4))) 230 vertex_data.append({'co': co, 'normal': no, 'uv': uv, 'extra_uvs': extra_uvs}) 231 if self.is_remove_doubles: 232 comparison_data = list(hash(repr(v['co']) + " " + repr(v['normal'])) for v in vertex_data) 233 comparison_counter = Counter(comparison_data) 234 comparison_data = list((comparison_counter[h] > 1) for h in comparison_data) 235 del comparison_counter 236 print(f_("Reading unknown count at 0x{num:02X}", num=reader.tell())) 237 unknown_count = struct.unpack('<i', reader.read(4))[0] 238 for i in range(unknown_count): 239 struct.unpack('<4f', reader.read(4 * 4)) 240 for i in range(vertex_count): 241 indexes = struct.unpack('<4H', reader.read(4 * 2)) 242 values = struct.unpack('<4f', reader.read(4 * 4)) 243 vertex_data[i]['weights'] = list({ 244 'index': index, 245 'value': value, 246 'name': local_bone_data[index]['name'], 247 } for index, value in zip(indexes, values)) 248 context.window_manager.progress_update(0.5) 249 # 面情報読み込み 250 face_data = [] 251 for i in range(mesh_count): 252 face_count = int(struct.unpack('<i', reader.read(4))[0] / 3) 253 datum = [tuple(reversed(struct.unpack('<3H', reader.read(3 * 2)))) for j in range(face_count)] 254 face_data.append(datum) 255 context.window_manager.progress_update(0.6) 256 257 # マテリアル情報読み込み 258 # TODO MaterialHandlerに変更 259 material_data = [] 260 material_count = struct.unpack('<i', reader.read(4))[0] 261 for i in range(material_count): 262 print(f_("mate count: {num} of {count} @ 0x{pos:02X}", num=i, count=material_count, pos=reader.tell())) 263 data = cm3d2_data.MaterialHandler.read(reader, read_header=False, version=model_ver) 264 data.name1 = data.name.lower() 265 material_data.append(data) 266 267 # name1 = common.read_str(reader) 268 # name2 = common.read_str(reader) 269 # name3 = common.read_str(reader) 270 # data_list = [] 271 # material_data.append({'name1': name1, 'name2': name2, 'name3': name3, 'data': data_list}) 272 # while True: 273 # data_type = common.read_str(reader) 274 # if data_type == 'tex': 275 # data_item = {'type': data_type} 276 # data_list.append(data_item) 277 # data_item['name'] = common.read_str(reader) 278 # data_item['type2'] = common.read_str(reader) 279 # if data_item['type2'] == 'tex2d': 280 # data_item['name2'] = common.read_str(reader) 281 # data_item['path'] = common.read_str(reader) 282 # data_item['tex_map'] = struct.unpack('<4f', reader.read(4*4)) 283 # elif data_type == 'col': 284 # name = common.read_str(reader) 285 # col = struct.unpack('<4f', reader.read(4*4)) 286 # data_list.append({'type': data_type, 'name': name, 'color': col}) 287 # elif data_type == 'f': 288 # name = common.read_str(reader) 289 # fval = struct.unpack('<f', reader.read(4))[0] 290 # data_list.append({'type': data_type, 'name': name, 'float': fval}) 291 # else: 292 # break 293 294 context.window_manager.progress_update(0.8) 295 296 # その他情報読み込み 297 misc_data = [] 298 while True: 299 #print(f_("Reading data_type at 0x{num:02X}", num=reader.tell())) 300 data_type = common.read_str(reader) 301 if data_type == 'morph': 302 misc_item = {'type': data_type} 303 misc_data.append(misc_item) 304 misc_item['name'] = common.read_str(reader) 305 misc_item['data'] = data_list = [] 306 morph_vert_count = struct.unpack('<i', reader.read(4))[0] 307 morph_extra_uvs = False 308 if model_ver >= 2102: # CR Edit Mode 309 morph_extra_uvs = struct.unpack('<?', reader.read(1))[0] 310 misc_item['uvs'] = [] 311 print(f_("{morph}.morph_extra_uvs @ 0x{pos:02X} = {bool}", morph=misc_item['name'], bool=morph_extra_uvs, pos=reader.tell()-1)) 312 for i in range(morph_vert_count): 313 index = struct.unpack('<H', reader.read(2))[0] 314 co = mathutils.Vector(struct.unpack('<3f', reader.read(3 * 4))) 315 normal = struct.unpack('<3f', reader.read(3 * 4)) 316 extra_uvs = () # CR Edit 317 if morph_extra_uvs: 318 extra_uvs = struct.unpack('<4f', reader.read(4 * 4)) 319 data_list.append({'index': index, 'co': co, 'normal': normal, 'color': extra_uvs}) 320 else: 321 break 322 323 except UnicodeDecodeError as e: 324 msg = [ 325 f_tip_("Error reading file at byte 0x{num:02X}", num=reader.tell()-len(e.object)) + "\n", 326 str(e) + "\n", 327 *traceback.format_tb(e.__traceback__) 328 ] 329 self.report(type={'ERROR'}, message="".join(reversed(msg))[0:-1]) 330 print("".join(msg)) 331 return {'CANCELLED'} 332 333 except struct.error as e: 334 msg = [ 335 f_tip_("Error reading file at byte 0x{num:02X}", num=reader.tell()) + "\n", 336 str(e) + "\n", 337 *traceback.format_tb(e.__traceback__) 338 ] 339 self.report(type={'ERROR'}, message="".join(reversed(msg))[0:-1]) 340 print("".join(msg)) 341 return {'CANCELLED'} 342 343 except common.CM3D2ImportException as e: 344 msg = [ 345 f_tip_("Error reading file at byte 0x{num:02X}", num=reader.tell()) + "\n", 346 str(e) + "\n", 347 *traceback.format_tb(e.__traceback__) 348 ] 349 self.report(type={'ERROR'}, message="".join(reversed(msg))[0:-1]) 350 print("".join(msg)) 351 return {'CANCELLED'} 352 353 context.window_manager.progress_update(1) 354 355 try: 356 bpy.ops.object.mode_set(mode='OBJECT') 357 except RuntimeError: 358 pass 359 bpy.ops.object.select_all(action='DESELECT') 360 361 # アーマチュア作成 362 if self.is_armature: 363 arm = bpy.data.armatures.new(model_name1 + ".armature") 364 arm_ob = bpy.data.objects.new (model_name1 + ".armature", arm) 365 compat.link(bpy.context.scene, arm_ob) 366 compat.set_select(arm_ob, True) 367 compat.set_active(context, arm_ob) 368 369 arm.show_names = prefs.show_bone_names 370 arm.show_axes = prefs.show_bone_axes 371 arm.show_bone_custom_shapes = prefs.show_bone_custom_shapes 372 arm.show_group_colors = prefs.show_bone_group_colors 373 if compat.IS_LEGACY: 374 arm_ob.show_x_ray = prefs.show_bone_in_front 375 else: 376 arm_ob.show_in_front = prefs.show_bone_in_front 377 378 bpy.ops.object.mode_set(mode='EDIT') 379 380 is_odd_scale_bone = False 381 382 # 基幹ボーンのみ作成 383 child_data = [] 384 for data in bone_data: 385 if not data['parent_name']: 386 bone = arm.edit_bones.new(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 387 bone.head, bone.tail = (0, 0, 0), (0, 1, 0) 388 bone.use_deform = False 389 390 #co.x, co.y, co.z = -co.x, co.z, -co.y 391 #rot = compat.mul(rot, mathutils.Quaternion((0, 0, 1), math.radians(90))) 392 #rot.w, rot.x, rot.y, rot.z = -rot.w, -rot.x, rot.z, -rot.y 393 394 #co = data['co' ].copy() 395 #rot = data['rot'].copy() 396 #co.x, co.y, co.z = -co.x, -co.z, co.y 397 #rot.w, rot.x, rot.y, rot.z = -rot.w, -rot.x, -rot.z, rot.y 398 ##rot = compat.mul(rot, mathutils.Quaternion((0, 0, 1), math.radians(-90))) 399 #rot = compat.convert_cm_to_bl_bone_rotation(rot) 400 #mat = compat.mul(mathutils.Matrix.Translation(co), rot.to_matrix().to_4x4()) 401 402 co_mat = mathutils.Matrix.Translation(data['co'].copy() * self.scale) 403 rot = mathutils.Quaternion(data['rot'].copy()) 404 #rot = compat.convert_cm_to_bl_bone_rotation(rot) 405 rot_mat = rot.to_matrix().to_4x4() 406 #rot_mat = compat.convert_cm_to_bl_bone_rotation(rot_mat) 407 mat = compat.mul(co_mat, rot_mat) 408 mat = compat.convert_cm_to_bl_bone_rotation(mat) 409 mat = compat.convert_cm_to_bl_space(mat) 410 #mat = compat.mul(mat, compat.CM_TO_BL_LOCAL_BONE_MAT4) 411 412 413 #fix_mat_scale = mathutils.Matrix.Scale(-1, 4, (1, 0, 0)) 414 #fix_mat_before = mathutils.Euler((math.radians(90), 0, 0), 'XYZ').to_matrix().to_4x4() 415 #fix_mat_after = mathutils.Euler((0, 0, math.radians(90)), 'XYZ').to_matrix().to_4x4() 416 417 #compat.set_bone_matrix(bone, compat.mul4(fix_mat_scale, fix_mat_before, mat, fix_mat_after)) 418 compat.set_bone_matrix(bone, mat) 419 420 421 bone["cm3d2_scl_bone"] = 1 if data['scl'] else 0 422 if 'scale' in data: 423 bone['cm3d2_bone_scale'] = data['scale'] 424 scale = mathutils.Vector(data['scale']) 425 if ( scale - mathutils.Vector((1,1,1)) ).length > 1e-5: 426 is_odd_scale_bone = True 427 self.report(type={'WARNING'}, message=f_tip_("Bone '{bone_name}' has odd scale '{bone_scale}' (odd by {bone_diff})", bone_name=bone.name, bone_scale=scale, bone_diff=( scale - mathutils.Vector((1,1,1)) ).length)) 428 scale *= self.scale * 0.01 429 scale = compat.convert_cm_to_bl_bone_rotation(scale) 430 bone.bbone_x = scale.x 431 bone.bbone_z = scale.z 432 #look = bone.tail - bone.head 433 #look *= scale.y 434 #bone.tail = look + bone.head 435 else: 436 child_data.append(data) 437 context.window_manager.progress_update(1.333) 438 439 # 子ボーンを追加していく 440 while len(child_data): 441 data = child_data.pop(0) 442 parent = arm.edit_bones.get(common.decode_bone_name(data['parent_name'], self.is_convert_bone_weight_names)) 443 if parent: 444 bone = arm.edit_bones.new(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 445 bone.parent = parent 446 bone.head, bone.tail = (0, 0, 0), (0, 1, 0) 447 bone.use_deform = False 448 449 #parent_mats = [] 450 #current_bone = bone 451 #while current_bone: 452 # for b in bone_data: 453 # if common.decode_bone_name(b['name'], self.is_convert_bone_weight_names) == current_bone.name: 454 # local_co = b['co' ].copy() 455 # local_rot = b['rot'].copy() 456 # break 457 # 458 # local_co_mat = mathutils.Matrix.Translation(local_co) 459 # local_rot_mat = local_rot.to_matrix().to_4x4() 460 # parent_mats.append(compat.mul(local_co_mat, local_rot_mat)) 461 # 462 # current_bone = current_bone.parent 463 #parent_mats.reverse() 464 # 465 #mat = mathutils.Matrix() 466 #for local_mat in parent_mats: 467 # mat = compat.mul(mat, local_mat) 468 #mat *= self.scale 469 #mat = compat.convert_cm_to_bl_space(mat) 470 #mat = compat.convert_cm_to_bl_bone_rotation(mat) 471 472 #parent_mat = compat.mul( 473 # mathutils.Matrix.Translation(parent.matrix.to_translation()), 474 # parent.matrix.to_quaternion().to_matrix().to_4x4() 475 #) 476 477 parent_mat = parent.matrix 478 479 local_co = data['co' ].copy() * self.scale 480 local_rot = data['rot'].copy() 481 #local_rot = compat.convert_cm_to_bl_bone_rotation(rot) 482 local_co_mat = mathutils.Matrix.Translation(local_co) 483 local_rot_mat = local_rot.to_matrix().to_4x4() 484 local_mat = compat.mul(local_co_mat, local_rot_mat) 485 local_mat = compat.convert_cm_to_bl_bone_space(local_mat) 486 #local_mat = compat.mul(local_mat, mathutils.Matrix.Diagonal((1,1,1)).to_4x4()) 487 mat = compat.mul(parent_mat, local_mat) 488 mat = compat.convert_cm_to_bl_bone_rotation(mat) 489 490 491 #co_mat = compat.mul( parent.matrix.inverted(), compat.convert_cm_to_bl_local_bone_mat4(local_co_mat) ) 492 #rot_mat = compat.mul( local_rot_mat, compat.CM_TO_BL_LOCAL_BONE_MAT4 ) 493 #mat = compat.ul(co_mat, rot_mat) 494 #local_mat = compat.mul(local_co_mat, local_rot_mat) 495 #local_mat *= self.scale 496 #mat = compat.mul( parent.matrix, compat.convert_cm_to_bl_local_bone(local_mat) ) 497 #mat *= self.scale 498 499 #mat *= self.scale 500 501 #co.x, co.y, co.z = -co.y, co.z, co.x 502 #rot.w, rot.x, rot.y, rot.z = rot.w, rot.y, -rot.z, -rot.x 503 504 #co = data['co' ].copy() * self.scale 505 #rot = data['rot'].copy() 506 #co.x, co.y, co.z = co.z, -co.x, co.y 507 ##co = compat.convert_cm_to_bl_local_bone(co) 508 ##rot.w, rot.x, rot.y, rot.z = rot.w, -rot.z, rot.x, -rot.y 509 ##rot.w, rot.x, rot.y, rot.z = rot.w, -rot.z, rot.x, -rot.y 510 #local_mat = compat.mul(mathutils.Matrix.Translation(co), rot.to_matrix().to_4x4()) 511 #mat = compat.mul( parent.matrix, local_mat ) 512 ##mat *= self.scale 513 514 #fix_mat_scale = mathutils.Matrix.Scale(-1, 4, (1, 0, 0)) 515 #fix_mat_before = mathutils.Euler((math.radians(90), 0, 0), 'XYZ').to_matrix().to_4x4() 516 #fix_mat_after = mathutils.Euler((0, 0, math.radians(90)), 'XYZ').to_matrix().to_4x4() 517 518 #compat.set_bone_matrix(bone, compat.mul4(fix_mat_scale, fix_mat_before, mat, fix_mat_after)) 519 compat.set_bone_matrix(bone, mat) 520 521 bone['cm3d2_scl_bone'] = 1 if data['scl'] else 0 522 if 'scale' in data: 523 bone['cm3d2_bone_scale'] = data['scale'] 524 scale = mathutils.Vector(data['scale']) 525 if ( scale - mathutils.Vector((1,1,1)) ).length > 1e-5: 526 is_odd_scale_bone = True 527 self.report(type={'WARNING'}, message=f_tip_("Bone '{bone_name}' has odd scale '{bone_scale}' (odd by {bone_diff})", bone_name=bone.name, bone_scale=scale, bone_diff=( scale - mathutils.Vector((1,1,1)) ).length)) 528 scale *= self.scale * 0.01 529 bone.bbone_x = scale.x 530 bone.bbone_z = scale.z 531 #bone.bbone_segments = scale.y 532 #look = bone.tail - bone.head 533 #look *= scale.y 534 #bone.tail = look + bone.head 535 else: 536 child_data.append(data) 537 context.window_manager.progress_update(1.666) 538 539 # Configure bones in local bone data 540 is_local_bones_corrupt = False 541 base_bone = arm.edit_bones.get(common.decode_bone_name(model_name2, self.is_convert_bone_weight_names)) 542 base_bone_offset = base_bone.matrix.copy() 543 base_bone_offset = compat.mul(mathutils.Matrix.Scale(-1, 4, (1, 0, 0)), base_bone_offset) 544 base_bone_offset = compat.convert_bl_to_cm_bone_rotation(base_bone_offset) 545 print(base_bone_offset) 546 print(f"base_bone_offset @ I =\n{base_bone_offset @ mathutils.Matrix.Identity(4)}") 547 #base_bone_offset = mathutils.Matrix.Identity(4) # compat.mul(base_bone_mat.inverted(), base_bone_mat) 548 549 def setup_local_bone(bone, mat, isRoot=False): 550 pos = compat.transform_inverse(mat.transposed()).translation 551 mat.row[3] = (0.0, 0.0, 0.0, 1.0) 552 mat.translation = pos 553 mat.translation *= self.scale 554 offset_mat = mat.copy() 555 if not common.is_descendant_of(bone, base_bone): 556 mat = compat.mul(base_bone_offset, mat) 557 #mat.translation = mat.translation + base_bone_offset.translation 558 mat = compat.convert_cm_to_bl_bone_rotation(mat) 559 mat = compat.mul(mathutils.Matrix.Scale(-1, 4, (1, 0, 0)), mat) 560 561 562 # The matrices from the local bone data are more precise rotations, but make sure they aren't corrupted 563 old_pos, old_rot, old_scale = bone.matrix.decompose() 564 compat.set_bone_matrix(bone, mat) 565 new_pos, new_rot, new_scale = bone.matrix.decompose() 566 dif_pos = (new_pos-old_pos).length/self.scale 567 dif_rot = old_rot.rotation_difference(new_rot) 568 if dif_pos > 0.1 or dif_rot.w < .9: 569 print(dif_pos, dif_rot) 570 is_local_bones_corrupt = True 571 #self.report(type={'WARNING'}, message="Found potentially corrupt local bone data, please re-import with \"Use Local Bone Data\" disabled.") 572 return mat 573 574 for data in local_bone_data: 575 if self.is_use_local_bones and data['name'] == model_name2: 576 bone = arm.edit_bones.get(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 577 mat = mathutils.Matrix(data['matrix']) 578 print("Found base bone in local bone data!") 579 #base_bone_offset = compat.mul(compat.transform_inverse(base_bone_offset), setup_local_bone(bone, mat, isRoot=True)) 580 581 582 for data in local_bone_data: 583 bone = arm.edit_bones.get(common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 584 bone.use_deform = True 585 if self.is_use_local_bones and not data['name'] == model_name2: 586 mat = mathutils.Matrix(data['matrix']) 587 setup_local_bone(bone, mat) 588 589 590 def distOnRay(pos0, pos1, point): 591 w = point - pos0 592 d = (pos1 - pos0).normalized() 593 return w.dot(d) / d.dot(d) 594 595 # ボーン整頓 596 for bone in arm.edit_bones: 597 if len(bone.children) == 0: 598 if bone.parent: 599 bone.length = bone.parent.length * 0.5 600 else: 601 bone.length = 0.2 * self.scale 602 elif len(bone.children) == 1: 603 co = bone.children[0].head - bone.head 604 bone.length = co.length 605 elif len(bone.children) >= 2: 606 if bone.parent: 607 max_len = 0.0 608 for child_bone in bone.children: 609 if "Pelvis" in bone.name: 610 dist = (child_bone.head - bone.head).length 611 else: 612 dist = distOnRay(bone.head, bone.tail, child_bone.head) 613 if dist > max_len: 614 max_len = dist 615 bone.length = max_len 616 else: 617 bone.length = 0.2 * self.scale 618 for bone in arm.edit_bones: 619 if len(bone.children) == 0: 620 if bone.parent: 621 bone.length = bone.parent.length * 0.5 622 623 # Make sure no bones are length 0, otherwise blender deletes them 624 for bone in arm.edit_bones: 625 min_length = 0.0001 626 if bone.length < min_length: 627 bone.length = min_length 628 629 # 一部ボーン削除 630 if self.is_armature_clean: 631 for bone in arm.edit_bones: 632 for b in local_bone_data: 633 name = common.decode_bone_name(b['name'], self.is_convert_bone_weight_names) 634 if bone.name == name: 635 break 636 else: 637 arm.edit_bones.remove(bone) 638 639 arm.layers[16] = True 640 compat.set_display_type(arm, prefs.bone_display_type) 641 bpy.ops.armature.select_all(action='DESELECT') 642 bpy.ops.object.mode_set(mode='OBJECT') 643 if self.is_custom_bones: 644 print("Set custom bones") 645 for pose_bone in arm_ob.pose.bones: 646 pose_bone.custom_shape = custom_bone_ob 647 context.window_manager.progress_update(2) 648 649 if self.is_mesh: 650 ob, me = self.create_mesh(context, model_name1, vertex_data, face_data) 651 # オブジェクト変形 652 CNV_OT_align_to_cm3d2_base_bone.from_bone_data(ob, bone_data, local_bone_data, base_bone_name=model_name2, scale=self.scale) 653 context.window_manager.progress_update(3) 654 655 self.create_uvs(context, me, vertex_data, extra_uv_uses) 656 context.window_manager.progress_update(4) 657 658 self.create_vertex_groups(context, ob, vertex_data, local_bone_data) 659 context.window_manager.progress_update(5) 660 661 self.create_shapekeys(context, ob, misc_data) 662 context.window_manager.progress_update(6) 663 664 # マテリアル追加 665 progress_count_total = 0.0 666 for data in material_data: 667 progress_count_total += 1 #len(data['data']) 668 self.progress_plus_value = 1.0 / (progress_count_total if progress_count_total > 0.0 else 1.0) 669 self.progress_count = 6.0 670 671 face_seek = 0 672 mates_set = set() 673 override = context.copy() 674 override['object'] = ob 675 prefs = common.preferences() 676 for index, data in enumerate(material_data): 677 print(f_("material count: {num} of {count}", num=index, count=material_count)) 678 if prefs.mate_unread_same_value and data.name in mates_set: 679 continue 680 mates_set.add(data.name) 681 #common.preferences().mate_unread_same_value 682 bpy.ops.object.material_slot_add(override) 683 mate = context.blend_data.materials.new(data.name)#['name1']) 684 #mate['shader1'] = data['name2'] 685 #mate['shader2'] = data['name3'] 686 687 ob.material_slots[-1].material = mate 688 # 面にマテリアル割り当て 689 for i in range(face_seek, face_seek + len(face_data[index])): 690 me.polygons[i].material_index = index 691 face_seek += len(face_data[index]) 692 693 # テクスチャ追加 694 if compat.IS_LEGACY: 695 #self.create_mateprop_old(context, me, texes_set, mate, index, data) 696 cm3d2_data.MaterialHandler.apply_to_old(override, mate, data) 697 common.decorate_material(mate, self.is_decorate, me, index) 698 else: 699 #self.create_mateprop(context, me, texes_set, mate, index, data) 700 cm3d2_data.MaterialHandler.apply_to(override, mate, data) 701 common.decorate_material(mate, self.is_decorate, me, index) 702 common.setup_material(mate) 703 704 ob.active_material_index = 0 705 context.window_manager.progress_update(7) 706 707 # メッシュ整頓 708 pre_mesh_select_mode = context.tool_settings.mesh_select_mode[:] 709 710 # Too buggy on versions before 2.91 so just disable it outright 711 #if self.is_sharp and (compat.IS_LEGACY or bpy.app.version < (2, 91)): 712 # context.tool_settings.mesh_select_mode = (False, True, False) 713 # bpy.ops.object.mode_set(mode='EDIT') 714 # 715 # bpy.ops.mesh.select_non_manifold(extend=False, use_wire=True, use_boundary=True, use_multi_face=False, use_non_contiguous=False, use_verts=False) 716 # for is_comparison, vert in zip(comparison_data, me.vertices): 717 # if is_comparison: 718 # vert.select = False 719 # bpy.ops.mesh.mark_sharp(use_verts=False) 720 # 721 # bpy.ops.object.mode_set(mode='OBJECT') 722 723 can_mark_sharp = not compat.IS_LEGACY and bpy.app.version >= (2, 91) 724 725 if self.is_remove_doubles: 726 context.tool_settings.mesh_select_mode = (True, False, False) 727 bpy.ops.object.mode_set(mode='EDIT') 728 if not self.is_sharp or not can_mark_sharp: 729 bpy.ops.mesh.select_all(action='DESELECT') 730 bpy.ops.object.mode_set(mode='OBJECT') 731 for is_comparison, vert in zip(comparison_data, me.vertices): 732 if is_comparison: 733 vert.select = True 734 bpy.ops.object.mode_set(mode='EDIT') 735 else: 736 bpy.ops.mesh.select_all(action='SELECT') 737 738 if not can_mark_sharp: 739 bpy.ops.mesh.remove_doubles(threshold=0.000001/5 * self.scale) 740 else: 741 bpy.ops.mesh.remove_doubles(threshold=0.000001/5 * self.scale, use_sharp_edge_from_normals=self.is_sharp) 742 bpy.ops.object.mode_set(mode='OBJECT') 743 744 context.tool_settings.mesh_select_mode = pre_mesh_select_mode 745 746 if self.is_seam: 747 bpy.ops.object.mode_set(mode='EDIT') 748 bpy.ops.mesh.select_all(action='SELECT') 749 bpy.ops.uv.select_all(action='SELECT') 750 bpy.ops.uv.seams_from_islands() 751 bpy.ops.object.mode_set(mode='OBJECT') 752 bpy.ops.object.mode_set(mode='EDIT') 753 bpy.ops.mesh.select_all(action='DESELECT') 754 bpy.ops.object.mode_set(mode='OBJECT') 755 756 if self.is_armature: 757 mod = ob.modifiers.new("Armature", 'ARMATURE') 758 mod.object = arm_ob 759 compat.set_active(context, arm_ob) 760 bpy.ops.object.parent_set(type='OBJECT', keep_transform=True) 761 compat.set_active(context, ob) 762 context.window_manager.progress_update(8) 763 764 # マテリアル情報のテキスト埋め込み 765 if self.is_mate_data_text: 766 for index, data in enumerate(material_data): 767 txt_name = "Material:" + str(index) 768 if txt_name in context.blend_data.texts: 769 txt = context.blend_data.texts[txt_name] 770 txt.clear() 771 else: 772 txt = context.blend_data.texts.new(txt_name) 773 txt.write(data.to_text()) 774 775 # txt.write("1000" + "\n") 776 # txt.write(data['name1'].lower() + "\n") 777 # txt.write(data['name1'] + "\n") 778 # txt.write(data['name2'] + "\n") 779 # txt.write(data['name3'] + "\n") 780 # txt.write("\n") 781 # for tex_data in data['data']: 782 # txt.write(tex_data['type'] + "\n") 783 # if tex_data['type'] == 'tex': 784 # txt.write("\t" + tex_data['name'] + "\n") 785 # txt.write("\t" + tex_data['type2'] + "\n") 786 # if tex_data['type2'] == 'tex2d': 787 # txt.write("\t" + tex_data['name2'] + "\n") 788 # txt.write("\t" + tex_data['path'] + "\n") 789 # map_list = tex_data['tex_map'] 790 # tex_map = " ".join([str(map_list[0]), str(map_list[1]), str(map_list[2]), str(map_list[3])]) 791 # txt.write("\t" + tex_map + "\n") 792 # elif tex_data['type'] == 'col': 793 # txt.write("\t" + tex_data['name'] + "\n") 794 # col = " ".join([str(tex_data['color'][0]), str(tex_data['color'][1]), str(tex_data['color'][2]), str(tex_data['color'][3])]) 795 # txt.write("\t" + col + "\n") 796 # elif tex_data['type'] == 'f': 797 # txt.write("\t" + tex_data['name'] + "\n") 798 # txt.write("\t" + str(tex_data['float']) + "\n") 799 # txt.current_line_index = 0 800 context.window_manager.progress_update(9) 801 802 # ボーン情報のテキスト埋め込み 803 if self.is_bone_data_text: 804 if "BoneData" in context.blend_data.texts: 805 txt = context.blend_data.texts["BoneData"] 806 txt.clear() 807 else: 808 txt = context.blend_data.texts.new("BoneData") 809 for i, data in enumerate(bone_data): 810 s = ",".join([data['name'], str(data['scl']), ""]) 811 parent_index = data['parent_index'] 812 if -1 < parent_index: 813 s += bone_data[parent_index]['name'] + "," 814 else: 815 s += "None" + "," 816 s += " ".join([str(data['co'][0]), str(data['co'][1]), str(data['co'][2])]) + "," 817 s += " ".join([str(data['rot'][0]), str(data['rot'][1]), str(data['rot'][2]), str(data['rot'][3])]) 818 if model_ver >= 2001: 819 if 'scale' in data: 820 s += ",1," + " ".join(map(str, data['scale'])) 821 else: 822 s += ",0" 823 824 if self.is_bone_data_text: 825 txt.write(s + "\n") 826 if self.is_mesh and self.is_bone_data_obj_property: 827 ob["BoneData:" + str(i)] = s 828 if self.is_armature and self.is_bone_data_arm_property: 829 arm["BoneData:" + str(i)] = s 830 if self.is_bone_data_text: 831 txt['BaseBone'] = model_name2 832 txt.current_line_index = 0 833 context.window_manager.progress_update(10) 834 835 # ローカルボーン情報のテキスト埋め込み 836 if self.is_bone_data_text: 837 if "LocalBoneData" in context.blend_data.texts: 838 txt = context.blend_data.texts["LocalBoneData"] 839 txt.clear() 840 else: 841 txt = context.blend_data.texts.new("LocalBoneData") 842 for i, data in enumerate(local_bone_data): 843 s = data['name'] + "," 844 845 mat_list = list(data['matrix'][0]) 846 mat_list.extend(list(data['matrix'][1])) 847 mat_list.extend(list(data['matrix'][2])) 848 mat_list.extend(list(data['matrix'][3])) 849 for j, f in enumerate(mat_list): 850 mat_list[j] = str(f) 851 s += " ".join(mat_list) 852 853 if self.is_bone_data_text: 854 txt.write(s + "\n") 855 if self.is_mesh and self.is_bone_data_obj_property: 856 ob["LocalBoneData:" + str(i)] = s 857 if self.is_armature and self.is_bone_data_arm_property: 858 arm["LocalBoneData:" + str(i)] = s 859 if self.is_bone_data_text: 860 txt['BaseBone'] = model_name2 861 txt.current_line_index = 0 862 863 if self.is_mesh and self.is_bone_data_obj_property: 864 ob['BaseBone'] = model_name2 865 if model_ver >= 1000: 866 ob['ModelVersion'] = model_ver 867 if self.is_armature and self.is_bone_data_arm_property: 868 arm['BaseBone'] = model_name2 869 if model_ver >= 1000: 870 arm['ModelVersion'] = model_ver 871 context.window_manager.progress_end() 872 873 require_time = time.time() - start_time 874 filesize = os.path.getsize(self.filepath) 875 filesize_str = "バイト" 876 if 1024 * 1024 < filesize: 877 filesize = filesize / (1024 * 1024.0) 878 filesize_str = "MB" 879 elif 1024 < filesize: 880 filesize = filesize / 1024.0 881 filesize_str = "KB" 882 self.report(type={'INFO'}, message=f_tip_("modelのインポートが完了しました ({} {}/ {:.2f} 秒)", filesize, filesize_str, require_time)) 883 884 if is_odd_scale_bone: 885 self.report(type={'WARNING'}, message="Found bone with a scale not equal to 1.") 886 if is_local_bones_corrupt: 887 self.report(type={'ERROR'}, message="Found potentially corrupt local bone data, please re-import with \"Use Local Bone Data\" disabled.") 888 return {'FINISHED'}
def
create_mesh( self, context, model_name1, vertex_data, face_data) -> (<class 'bpy_types.Object'>, <class 'bpy_types.Mesh'>):
890 def create_mesh(self, context, model_name1, vertex_data, face_data) -> (bpy.types.Object, bpy.types.Mesh): 891 # メッシュ作成 892 me = context.blend_data.meshes.new(model_name1) 893 verts, faces = [], [] 894 for data in vertex_data: 895 #co = list(data['co'][:]) 896 #co[0] = -co[0] 897 #co[0] *= self.scale 898 #co[1] *= self.scale 899 #co[2] *= self.scale 900 co = compat.convert_cm_to_bl_space( mathutils.Vector(data['co']) * self.scale ) 901 #co = mathutils.Vector(data['co']) * self.scale 902 verts.append(co) 903 context.window_manager.progress_update(2.25) 904 for data in face_data: 905 faces.extend(data) 906 context.window_manager.progress_update(2.5) 907 me.from_pydata(verts, [], faces) 908 909 # オブジェクト化 910 ob = context.blend_data.objects.new(model_name1, me) 911 ob.rotation_mode = 'QUATERNION' 912 compat.link(context.scene, ob) 913 compat.set_select(ob, True) 914 compat.set_active(context, ob) 915 bpy.ops.object.shade_smooth() 916 context.window_manager.progress_update(2.75) 917 918 # Custom Split Normals 919 #normals_color = me.vertex_colors.new(name=f"Basis_normals", do_init=False) or me.vertex_colors[-1] 920 #for vert_index, vert in enumerate(vertex_data): 921 # no = compat.convert_cm_to_bl_space( mathutils.Vector(vert['normal']) ) #mathutils.Vector(vert['normal']) * mathutils.Vector((-1,1,1)) # 922 # no.normalize() 923 # print(no) 924 # for loop_index in vert_loops[vert_index]: 925 # #normals[loop_index] = no 926 # normals_color.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1) 927 # *no, #*(no * 0.5 + mathutils.Vector([0.5]*3)), 928 # 1, 929 # ) 930 #me.normals_split_custom_set(normals) 931 me.normals_split_custom_set_from_vertices( 932 tuple( 933 compat.convert_cm_to_bl_space( mathutils.Vector(vert['normal']) ) 934 for vert in vertex_data 935 ) 936 ) 937 me.use_auto_smooth = True 938 939 return ob, me
def
create_vertex_groups(self, context, ob, vertex_data, local_bone_data):
941 def create_vertex_groups(self, context, ob, vertex_data, local_bone_data): 942 # 頂点グループ作成 943 for data in local_bone_data: 944 ob.vertex_groups.new(name=common.decode_bone_name(data['name'], self.is_convert_bone_weight_names)) 945 context.window_manager.progress_update(4.333) 946 947 for vert_index, data in enumerate(vertex_data): 948 for weight in data['weights']: 949 if 0.0 < weight['value']: 950 vertex_group = ob.vertex_groups[common.decode_bone_name(weight['name'], self.is_convert_bone_weight_names)] 951 vertex_group.add([vert_index], weight['value'], 'REPLACE') 952 context.window_manager.progress_update(4.666) 953 954 if self.is_vertex_group_sort: 955 bpy.ops.object.vertex_group_sort(sort_type='NAME') 956 957 if self.is_remove_empty_vertex_group: 958 for vg in ob.vertex_groups[:]: 959 for vert in ob.data.vertices: 960 for group in vert.groups: 961 if group.group == vg.index: 962 if 0.0 < group.weight: 963 break 964 else: # if for-loop didn't break 965 continue 966 break 967 else: # if for-loop didn't break 968 ob.vertex_groups.remove(vg) 969 970 ob.vertex_groups.active_index = 0
def
create_uvs(self, context, me, vertex_data, extra_uv_uses):
972 def create_uvs(self, context, me, vertex_data, extra_uv_uses): 973 # UV作成 974 bm = bmesh.new() 975 bm.from_mesh(me) 976 bm.loops.layers.uv.new(f_data_("MainUV")) 977 for i, used in enumerate(extra_uv_uses): 978 if used: 979 bm.loops.layers.uv.new(f_data_("ExtraUV{num}", num=i)) 980 for face in bm.faces: 981 for loop in face.loops: 982 loop[bm.loops.layers.uv[0]].uv = vertex_data[loop.vert.index]['uv'] 983 for extra_uv_index, extra_uv in enumerate(vertex_data[loop.vert.index]['extra_uvs']): 984 loop[bm.loops.layers.uv[extra_uv_index+1]].uv = extra_uv 985 bm.to_mesh(me) 986 bm.free()
def
create_shapekeys(self, context, ob, misc_data):
988 def create_shapekeys(self, context, ob, misc_data): 989 # モーフ追加 990 me = ob.data 991 992 is_use_attributes = (not compat.IS_LEGACY and bpy.app.version >= (2,92)) 993 is_fast_create = (not compat.IS_LEGACY and bpy.app.version >= (3,2)) 994 995 #if not is_fast_create: 996 # bpy.ops.object.mode_set(mode='VERTEX_PAINT') 997 # prev_brush_color = context.tool_settings.vertex_paint.brush.color 998 999 vert_loops = dict() 1000 for loop_index, loop in enumerate(me.loops): 1001 vert_loops.setdefault(loop.vertex_index, list()).append(loop_index) 1002 1003 def fill_color_layer(layer, color): 1004 import numpy as np 1005 color_np = np.array(color, dtype=float) 1006 color_values = np.broadcast_to(color_np, (len(me.loops), len(color_np))) 1007 layer.data.foreach_set('color', color_values.ravel()) 1008 1009 def create_normals_color(name): 1010 default_color = (0.5, 0.5, 0.5, 1.0) 1011 1012 #if is_fast_create: 1013 # bpy.ops.geometry.color_attribute_add(name=name, domain='CORNER', data_type='FLOAT_COLOR', color=default_color) 1014 # return me.attributes.active 1015 1016 if is_use_attributes: 1017 normals_color = me.attributes.new(name, 'FLOAT_COLOR', 'CORNER') 1018 else: 1019 normals_color = me.vertex_colors.new(name=name, do_init=False) or me.vertex_colors[-1] 1020 1021 fill_color_layer(normals_color, default_color) 1022 1023 return normals_color 1024 1025 def create_unknown_color(data): 1026 unknown_color = None 1027 if len(data['data']) and data['data'][0]['color']: 1028 if is_use_attributes: 1029 unknown_color = me.attributes.new(f"{data['name']}_unknown", 'FLOAT_COLOR', 'CORNER') 1030 else: 1031 unknown_color = me.vertex_colors.new(name=f"{data['name']}_unknown", do_init=False) or me.vertex_colors[-1] 1032 return unknown_color 1033 1034 def set_shape_key_data(shape_key, normals_color, unknown_color): 1035 for vert in data['data']: 1036 vert_index = vert['index'] 1037 co = compat.convert_cm_to_bl_space( mathutils.Vector(vert['co']) * self.scale ) 1038 no = compat.convert_cm_to_bl_space( mathutils.Vector(vert['normal'])) 1039 shape_key.data[vert_index].co = shape_key.data[vert_index].co + co 1040 1041 write_vertex_colors(vert, no, normals_color, unknown_color) 1042 1043 def write_vertex_colors(vert, no, normals_color, unknown_color): 1044 for loop_index in vert_loops[vert['index']]: 1045 normals_color.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1) 1046 no[0] * 0.5 + 0.5, 1047 no[1] * 0.5 + 0.5, 1048 no[2] * 0.5 + 0.5, 1049 1, 1050 ) 1051 if not vert['color']: 1052 continue 1053 unknown_color.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1) 1054 vert['color'][0] * 0.5 * vert['color'][3] + 0.5, 1055 vert['color'][1] * 0.5 * vert['color'][3] + 0.5, 1056 vert['color'][2] * 0.5 * vert['color'][3] + 0.5, 1057 1, 1058 ) 1059 1060 morph_count = -1 1061 for data in misc_data: 1062 if not data['type'] == 'morph': 1063 continue 1064 1065 morph_count += 1 1066 1067 if morph_count == 0: 1068 bpy.ops.object.shape_key_add(from_mix=False) 1069 me.shape_keys.name = ob.name 1070 shape_key = ob.shape_key_add(name=data['name'], from_mix=False) 1071 1072 normals_color = create_normals_color(f"{data['name']}_delta_normals") 1073 unknown_color = create_unknown_color(data) 1074 set_shape_key_data(shape_key, normals_color, unknown_color)
def
create_mateprop_old(self, context, me, tex_set, mate, mate_idx, data: list):
1077 def create_mateprop_old(self, context, me, tex_set, mate, mate_idx, data: list): 1078 # create_matepropとの違いは、slot_indexの有無、nodeの接続・配置処理のみ 1079 1080 prefs = common.preferences() 1081 # テクスチャ追加 1082 slot_index = 0 1083 for tex_data in data['data']: 1084 if prefs.mate_unread_same_value: 1085 if tex_data['name'] in tex_set: 1086 continue 1087 tex_set.add(tex_data['name']) 1088 1089 node_name = tex_data['name'] 1090 if tex_data['type'] == 'tex': 1091 path = tex_data['path'] 1092 tex_map_data = tex_data['tex_map'] 1093 common.create_tex(context, mate, node_name, tex_data['name2'], path, path, tex_map_data, prefs.is_replace_cm3d2_tex, slot_index) 1094 1095 elif tex_data['type'] == 'col': 1096 col = tex_data['color'] 1097 common.create_col(context, mate, node_name, col, slot_index) 1098 1099 elif tex_data['type'] == 'f': 1100 f = tex_data['float'] 1101 common.create_f(context, mate, node_name, f, slot_index) 1102 1103 slot_index += 1 1104 1105 self.progress(context)
def
create_mateprop(self, context, me, tex_set, mate, mate_idx, data: list):
1107 def create_mateprop(self, context, me, tex_set, mate, mate_idx, data: list): 1108 if mate.use_nodes is False: 1109 mate.use_nodes = True 1110 1111 nodes = mate.node_tree.nodes 1112 prefs = common.preferences() 1113 1114 for prop_data in data['data']: 1115 if prefs.mate_unread_same_value: 1116 if prop_data['name'] in tex_set: 1117 continue 1118 tex_set.add(prop_data['name']) 1119 1120 if prop_data['type'] == 'tex': # テクスチャ追加 1121 prop_name = prop_data['name'] 1122 if prop_data['type2'] == 'tex2d': 1123 tex_name = prop_data['name2'] 1124 cm3d2path = prop_data['path'] 1125 tex_map = prop_data['tex_map'] 1126 tex = common.create_tex(context, mate, prop_name, tex_name, cm3d2path, cm3d2path, tex_map) 1127 1128 if prop_data['type2'] == 'tex2d': 1129 mapping = prop_data['tex_map'] 1130 tex_map = tex.texture_mapping 1131 tex_map.translation[0] = mapping[0] 1132 tex_map.translation[1] = mapping[1] 1133 tex_map.scale[0] = mapping[2] 1134 tex_map.scale[1] = mapping[3] 1135 1136 # ファイルの実体を割り当て 1137 if prefs.is_replace_cm3d2_tex: 1138 img = tex.image 1139 # col = mate.node_tree.nodes.new(type='ShaderNodeAttribute') 1140 # tex.image = bpy.data.images.load("C:\\path\\to\\im.jpg") 1141 replaced = common.replace_cm3d2_tex(img, self.texpath_dict, reload_path=False) 1142 if compat.IS_LEGACY and replaced and prop_name == '_MainTex': 1143 for face in me.polygons: 1144 if face.material_index == mate_idx: 1145 me.uv_textures.active.data[face.index].image = img 1146 else: 1147 common.create_tex(context, mate, prop_name) 1148 1149 elif prop_data['type'] == 'col': 1150 col = nodes.new(type='ShaderNodeRGB') 1151 col.name = col.label = prop_data['name'] 1152 # val.type = 'RGB' 1153 col.outputs[0].default_value = prop_data['color'][:4] 1154 1155 # mate.node_tree.links.new(bsdf.inputs['xxx'], val.outputs['Color']) 1156 # mate.node_tree.nodes.active = col 1157 1158 # slot = mate.texture_slots.create(tex_index) 1159 # mate.use_textures[tex_index] = False 1160 # slot.diffuse_color_factor = tex_data['color'][3] 1161 # slot.use_rgb_to_intensity = True 1162 # tex = context.blend_data.textures.new(tex_data['name'], 'BLEND') 1163 # slot.texture = tex 1164 1165 elif prop_data['type'] == 'f': 1166 val = nodes.new(type='ShaderNodeValue') 1167 val.name = prop_data['name'] 1168 val.label = prop_data['name'] 1169 # val.type = 'VALUE' 1170 # mate.node_tree.links.new(bsdf.inputs['xxx'], val.outputs['Value']) 1171 1172 val.outputs[0].default_value = prop_data['float'] 1173 1174 self.progress(context) 1175 1176 cm3d2_data.align_nodes(mate)
Inherited Members
- bpy_types.Operator
- as_keywords
- poll_message_set
- bpy_extras.io_utils.ImportHelper
- check
- builtins.bpy_struct
- keys
- values
- items
- get
- pop
- as_pointer
- keyframe_insert
- keyframe_delete
- driver_add
- driver_remove
- is_property_set
- property_unset
- is_property_readonly
- is_property_overridable_library
- property_overridable_library_set
- path_resolve
- path_from_id
- type_recast
- bl_rna_get_subclass_py
- bl_rna_get_subclass
- id_properties_ensure
- id_properties_clear
- id_properties_ui
- id_data